一线开发之策略模式的几种实现方式

前言

在一线开发中,需要快速完成业务需求开发,此时不可避免的出现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);
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。