2019独角兽企业重金招聘Python工程师标准>>>
场景描述:
我需要开发四个页面,每个页面都是只涉及增删改查的基本逻辑。
最简单的写法:
创建四个接口A,B,C,D,每个接口中都声明了增删改查四个方法,完全一致
public Map<String,Object> delete(HttpServletRequest request, User user);public Map<String,Object> query(HttpServletRequest request, User user, Map<String, Object> params);public Map<String,Object> insert(HttpServletRequest request, User user);public Map<String,Object> update(HttpServletRequest request, User user);
为上面四个接口分别创建四个实现类,复写接口中的增删改查方法
接口A的实现类
@Override
public Map<String, Object> delete(HttpServletRequest request, User user) {Map<String,Object> params = new HashMap<String,Object>();params.put("operation", "delete");return commandExecutor.execute(new DaoAImpl(request, params, user));
}
@Override
public Map<String, Object> query(HttpServletRequest request, User user, Map<String, Object> params) {params = null == params ? new HashMap<String,Object>() : params;params.put("operation", "query");return commandExecutor.execute(new DaoAImpl(request, params, user));
}
@Override
public Map<String, Object> insert(HttpServletRequest request, User user) {Map<String,Object> params = new HashMap<String,Object>();params.put("operation", "insert");return commandExecutor.execute(new DaoAImpl(request, params, user));
}
@Override
public Map<String, Object> update(HttpServletRequest request, User user) {Map<String,Object> params = new HashMap<String,Object>();params.put("operation", "update");return commandExecutor.execute(new DaoAImpl(request, params, user));
}
接口B的实现类
@Override
public Map<String, Object> delete(HttpServletRequest request, User user) {Map<String,Object> params = new HashMap<String,Object>();params.put("operation", "delete");return commandExecutor.execute(new DaoBImpl(request, params, user));
}
@Override
public Map<String, Object> query(HttpServletRequest request, User user, Map<String, Object> params) {params = null == params ? new HashMap<String,Object>() : params;params.put("operation", "query");return commandExecutor.execute(new DaoBImpl(request, params, user));
}
@Override
public Map<String, Object> insert(HttpServletRequest request, User user) {Map<String,Object> params = new HashMap<String,Object>();params.put("operation", "insert");return commandExecutor.execute(new DaoBImpl(request, params, user));
}
@Override
public Map<String, Object> update(HttpServletRequest request, User user) {Map<String,Object> params = new HashMap<String,Object>();params.put("operation", "update");return commandExecutor.execute(new DaoBImpl(request, params, user));
}
接口C,D 的实现类就不在展示了。其中主要区别就是:
ServiceAImpl调用DaoAImpl的对象
ServiceBImpl调用DaoBImpl的对象
ServiceCImpl调用DaoCImpl的对象
ServiceDImpl调用DaoDImpl的对象
看完上面的代码,你可以发现,重复的代码太多了,需要整理下
解决方案:
接口:可以将增删改查的方法声明放到一个基础接口中,然后继承这个基础接口就行。
基础service接口
package com.engine.odoc.service;import java.util.Map;import javax.servlet.http.HttpServletRequest;import weaver.hrm.User;public interface BaseService {public Map<String,Object> delete(HttpServletRequest request, User user);public Map<String,Object> query(HttpServletRequest request, User user, Map<String, Object> params);public Map<String,Object> insert(HttpServletRequest request, User user);public Map<String,Object> update(HttpServletRequest request, User user);
}
继承基础service接口的接口
package com.engine.odoc.service;public interface ServiceA extends BaseService {}
package com.engine.odoc.service;public interface ServiceB extends BaseService {}
package com.engine.odoc.service;public interface ServiceC extends BaseService {}
package com.engine.odoc.service;public interface ServiceD extends BaseService {}
接口的实现:同样是增删改查四个复写的方法,唯一不同的就是不同的实现类调用不同的持久层(DAO)对象。期初的想法与处理接口的想法一样,把复写的增删改查方法写到一个基础service实现类中,然后继承这个基础service实现类即可。
为了能实现这个功能,我们需要用到Java中的泛型和反射知识
新建一个基础service实现类
package com.engine.odoc.service.impl;public class BaseServiceImpl<T> implements BaseService {@Overridepublic Map<String, Object> delete(HttpServletRequest request, User user) {}@Overridepublic Map<String, Object> query(HttpServletRequest request, User user, Map<String, Object> params) {}@Overridepublic Map<String, Object> insert(HttpServletRequest request, User user) {}@Overridepublic Map<String, Object> update(HttpServletRequest request, User user) {}}
可以看到这个基础service实现类接受了一个类型参数T
那些继承了这个基础实现类的类,就可以通过这个类型参数,把需要调用的Dao层对象的类型传递到父类当中
package com.engine.odoc.service.impl;public class ServiceAImpl extends BaseServiceImpl<DaoAImpl> implements ServiceA {}
package com.engine.odoc.service.impl;public class ServiceBImpl extends BaseServiceImpl<DaoBImpl> implements ServiceB {}
package com.engine.odoc.service.impl;public class ServiceCImpl extends BaseServiceImpl<DaoCImpl> implements ServiceC {}
package com.engine.odoc.service.impl;public class ServiceDImpl extends BaseServiceImpl<DaoDImpl> implements ServiceD {}
接下来,我们需要思考的是,如何通过这个类型参数T,来得到T的一个实例。
我们先上菜
package com.engine.odoc.service.impl;import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;import javax.servlet.http.HttpServletRequest;import com.engine.odoc.service.BaseService;public class BaseServiceImpl<T> implements BaseService {public Class cusClass;public BaseServiceImpl() {// 获取T.classType genericSuperclass = this.getClass().getGenericSuperclass();if(genericSuperclass instanceof ParameterizedType) {ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;Type[] typeArray = parameterizedType.getActualTypeArguments();if(null != typeArray && typeArray.length>0) {cusClass = (Class) typeArray[0];}}}/*** 获取T类的实例* @param request* @param params* @param user* @return*/private T getTInstance(HttpServletRequest request, Map<String,Object> params, User user) {try {return (T) cusClass.getConstructor(new Class[]{HttpServletRequest.class, Map.class, User.class}).newInstance(request, params, user);} catch (Exception e) {e.printStackTrace();}return null;}@Overridepublic Map<String, Object> delete(HttpServletRequest request, User user) {}@Overridepublic Map<String, Object> query(HttpServletRequest request, User user, Map<String, Object> params) {}@Overridepublic Map<String, Object> insert(HttpServletRequest request, User user) {}@Overridepublic Map<String, Object> update(HttpServletRequest request, User user) {}}
我们可以看到,我们在这个基础service实现类的默认构造函数中确认了类型参数T的类型,得到T.class。之后在getTInstance() 方法中通过反射的方式获取了T的实例。
Type genericSuperclass = this.getClass().getGenericSuperclass();
这行代码我们是写在父类(BaseServiceImpl)的默认构造函数中的。继承这个类的子类们,在执行默认构造函数的时候,会先执行super();调用父类的默认构造函数,这时候,以上这行代码中的this就代表了子类,调用getGenericSuperclass()来获得父类(BaseServiceImpl),而得到的父类(BaseServiceImpl)可能是BaseServiceImpl<DaoAImpl>,BaseServiceImpl<DaoBImpl>... ,也可能BaseServiceImpl<T>。
我们可以使用接口ParameterizedType,用来检验类型参数是否被参数化
Type genericSuperclass = this.getClass().getGenericSuperclass();
if(genericSuperclass instanceof ParameterizedType) {// 该泛型类的类型参数已经被参数化
}
如果类型参数已经被参数化,我们就可以通过调用下面的方法
package java.lang.reflect;public interface ParameterizedType extends Type {Type[] getActualTypeArguments();
}
返回的数组中就存储了类型参数T的具体类型,即T.class
获取到T.class之后,我们就可以通过反射来进一步获得T的实例
try {return (T) cusClass.getConstructor(new Class[]{HttpServletRequest.class, Map.class, User.class}).newInstance(request, params, user);
} catch (Exception e) {e.printStackTrace();
}