前言
在一线开发中,需要快速完成业务需求开发,此时不可避免的出现if...else..这种硬编码判断逻辑,当代码包含大量这种结构时会降低代码的可读性,扩展性,并且不易维护,策略模式是解决这种问题的好办法,并且符合开闭原则,本文由简入深介绍我平常使用最多的几种策略模式的实现。
场景
一个订单处理场景,根据不同订单的类型有不同的订单金额计算方式
public interface CalcOrderService {
/**
* 根据不同type的订单有不同的计算金额方式
* @param type
* @return
*/
String calc(String type);
}
基于spring xml配置的实现
1.策略接口定义
public interface OrderCalcHandler {
/**
* 根据type进行不同类型的订单金额计算
* @param type
* @return
*/
String handler();
}
2.策略实现
@Service(value = "aOrderCalcHandler")
public class AOrderCalcHandler implements OrderCalcHandler{
@Override
public String handler() {
return "AOrderCalcHandler: ok";
}
}
@Service(value = "bOrderCalcHandler")
public class BOrderCalcHandler implements OrderCalcHandler{
@Override
public String handler() {
return "BOrderCalcHandler: ok";
}
}
3.组装策略上下文
public class OrderCalcHandlerContext {
private Map<String, OrderCalcHandler> handlerMap;
public void setHandlerMap(Map<String, OrderCalcHandler> handlerMap) {
this.handlerMap = handlerMap;
}
public OrderCalcHandler selectHandler(String type) {
return handlerMap.get(type);
}
}
<bean id="orderCalcHandlerContext" class="niaochao.policy.OrderCalcHandlerContext">
<property name="handlerMap">
<map>
<entry key="typeA" value-ref="aOrderCalcHandler"/>
<entry key="typeB" value-ref="bOrderCalcHandler"/>
</map>
</property>
</bean>
4.在场景上的使用
@Service
public class CalcOrderServiceImpl implements CalcOrderService{
@Autowired
private OrderCalcHandlerContext orderCalcHandlerContext;
@Override
public String calc(String type) {
return orderCalcHandlerContext.selectHandler(type).handler();
}
}
使用注解进行不同的策略组装
1.定义一个注解,注解的value可以包含多个不同的金额计算策略,所以是个数组
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface HandlerSelector {
String[] value() default {};
}
2.定义抽象的金额计算策略
public abstract class AbstractCalcHandler {
public abstract String execute();
public abstract boolean accept(String type);
}
3.金额计算策略实现
@Service(value = "aCalcHandler")
public class ACalcHandler extends AbstractCalcHandler{
@Override
public String execute() {
return "ACalcHandler calc";
}
@Override
public boolean accept(String type) {
return "typeA".equals(type);
}
}
@Service(value = "bCalcHandler")
public class BCalcHandler extends AbstractCalcHandler{
@Override
public String execute() {
return "BCalcHandler calc";
}
@Override
public boolean accept(String type) {
return "typeB".equals(type);
}
}
4.抽象策略选择器:会自动的根据订单type来选择合适的处理器,主要通过策略实现中的accept方法
public abstract class AbstractHandlerSelector {
private List<AbstractCalcHandler> handlers;
public void setHandlers(List<AbstractCalcHandler> handlers) {
this.handlers = handlers;
}
public String execute(String type) {
AbstractCalcHandler handler = selectHandler(type);
if (handler == null) {
throw new RuntimeException("can not find handler");
}
return handler.execute();
}
private AbstractCalcHandler selectHandler(String type) {
if (CollectionUtils.isEmpty(handlers)) {
return null;
}
return handlers.stream().filter(handler -> handler.accept(type))
.findFirst().orElse(null);
}
}
5.定义策略选择处理器,通过继承上面的抽象策略选择器,我们业务中可以定义多个包含不同的策略选择器
@HandlerSelector({
"aCalcHandler","aCalcHandler"
})
@Service
public class HandlerContext extends AbstractHandlerSelector{
}
6.关键来了,我们如何将策略组装到策略选择器呢?如下:
@Service
public class CalcHandlerProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean.getClass().isAnnotationPresent(HandlerSelector.class)) {
Class<?> clazz = bean.getClass();
HandlerSelector selector = clazz.getAnnotation(HandlerSelector.class);
String[] handlerNames = selector.value();
if (ArrayUtils.isNotEmpty(handlerNames)) {
List<AbstractCalcHandler> handlers = Arrays.stream(handlerNames)
.map(handlerName -> {
//继承ApplicationContextAware,自己实现一个ApplicationContext
AbstractCalcHandler handler = ApplicationContext.getBean(handlerName);
return handler;
})
.collect(Collectors.toList());
//将不同的策略注入策略选择器
((AbstractHandlerSelector)bean).setHandlers(handlers);
}
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
从bean(HandlerContext)中拿到HandlerSelector注解中的策略,并将策略实例化后注入到handlers集合中
7.在场景上的使用
@Service
public class CalcOrderServiceImpl implements CalcOrderService {
@Autowired
private HandlerContext handlerContext;
@Override
public String calc(String type) {
return handlerContext.execute(type);
}
}