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();
}
?
?
?
?