今天我們來了解下設計模式中比較常用的策略模式
什么是策略模式?
策略模式定義了一系列的算法,並將每一個算法封裝起來,使每個算法可以相互替代,使算法本身和使用算法的客戶端分割開來,相互獨立。(摘自百度)
策略模式適用於什么場景?
一個大功能,它有許多不同類型的實現(策略類),具體根據客戶端來決定采用特定的策略類。
比如下單、物流對接、網關的加簽驗簽等。
以物流對接為例來比較簡單工廠模式和策略模式。
具體業務為每個物流公司都有它們對應的code,加簽方法,物流查詢方法
首先我們定義好接口類
public interface Logistics {
/**
* 物流公司唯一標識
* @return
*/
String companyCode();
/**
* 加簽
* @param request
*/
String sign(SignRequest request);
/**
* 查詢物流信息
*/
LogisticsInfoResponse queryLogisticsInfo(QueryLogisticsInfoRequest request);
}
對接順風和圓通
@service("shunfengLogistics")
public class ShunfengLogistics implements Logistics {
@Override
public String companyCode() {
return "shunfeng";
}
@Override
public String sign(SignRequest request) {
//do your biz
return null;
}
@Override
public LogisticsInfoResponse queryLogisticsInfo(QueryLogisticsInfoRequest request) {
//do your biz
return null;
}
}
@service("yuantongLogistics")
public class YuantongLogistics implements Logistics {
@Override
public String companyCode() {
return "yuantong";
}
@Override
public String sign(SignRequest request) {
//do your biz
return null;
}
@Override
public LogisticsInfoResponse queryLogisticsInfo(QueryLogisticsInfoRequest request) {
//do your biz
return null;
}
}
簡單工廠模式
public class LogisticsFactory {
@Autowired
private Logistics shunfengLogistics;
@Autowired
private Logistics yuantongLogistics;
public Logistics getLogistics(LogisticsRequest request) {
String company = request.getCompanyCode();
if ("shunfeng".equals(company)) {
return shunfengLogistics;
}
if ("yuantong".equals(company)) {
return yuantongLogistics;
}
throw new BizException("物流公司類型錯誤");
}
}
每當我們接入一家物流公司的時候都要使LogisticsFactory加一段if分支。這就違反了設計模式的開閉原則
策略模式結合Spring特性
其實不結合Spring特性的話,策略模式還是有上述問題存在。
我們先來准備下spring相關知識
1.實現InitializingBean接口。相信這個大家並不陌生。就是spring容器創建bean的時候幫你執行初始化的接口
2.實現ApplicationContextAware接口。通俗的講,實現了這個接口的bean相當於是拿到了ApplicationContext,相當於整個spring容器的資源。
3.ApplicationContext接口的getBeansOfType方法。獲取整個spring容器中某個類型的bean,返回的是map類型。key對應beanName, value對應bean。
@Component
public class LogisticsResolver implements InitializingBean, ApplicationContextAware {
private ApplicationContext applicationContext;
private Map<String, Sign> logisticsHandlerMap = new HashMap<>();
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public void afterPropertiesSet() {
Map<String, Sign> beanMap = applicationContext.getBeansOfType(Logistics.class);
for (String key : beanMap.keySet()) {
this.logisticsHandlerMap.put(beanMap.get(key).companyCode(), beanMap.get(key));
}
}
public Logistics getHandler(String companyCode) {
return logisticsHandlerMap.get(companyCode);
}
}
通過spring容器去獲取對應的所有實現類,並組裝成我們想要的companyCode→bean的map。通過getHandler方法就能拿到對應的實現類。
但是現在我們每次加一個策略類的時候都交由Spring去管理,只管加就行了