今天我们来了解下设计模式中比较常用的策略模式
什么是策略模式?
策略模式定义了一系列的算法,并将每一个算法封装起来,使每个算法可以相互替代,使算法本身和使用算法的客户端分割开来,相互独立。(摘自百度)
策略模式适用于什么场景?
一个大功能,它有许多不同类型的实现(策略类),具体根据客户端来决定采用特定的策略类。
比如下单、物流对接、网关的加签验签等。
以物流对接为例来比较简单工厂模式和策略模式。
具体业务为每个物流公司都有它们对应的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.signHandlerMap.put(beanMap.get(key).companyCode(), beanMap.get(key));
}
}
public Logistics getHandler(String companyCode) {
return logisticsHandlerMap.get(companyCode);
}
}
通过spring容器去获取对应的所有实现类,并组装成我们想要的companyCode→bean的map。通过getHandler方法就能拿到对应的实现类。
但是现在我们每次加一个策略类的时候都交由Spring去管理,只管加就行了