使用策略模式如何干掉大片的 if else

原文地址  http://www.54288.top/article/view.do?articleId=130

原文地址  http://www.54288.top/article/view.do?articleId=130

原文地址  http://www.54288.top/article/view.do?articleId=130

原文地址  https://www.xujd.top/article/view.do?articleId=130

原文地址  https://www.xujd.top/article/view.do?articleId=130

需求

这里虚拟一个业务需求,让大家容易理解。假设有一个OA系统,里面的一个功能根据不
同的流程做不同的处理,比如有合同流程,请假流程,印章申请流程,出差申请。外出流程,报销流程等等很多。

传统实现
根据类型写一堆的if else:
public String handle(Process process){
  if(process.type="1"){//请假}
  else if(process.type="2"){//合同}
  ....
  else{}
}
这样就会导致这个class/method很庞大,维护性很差。

使用策略模式实现

策略模式的重心:是如何实现算法,而是如何组织,调用算法,让程序更加灵活,具有更
好的可维护性和扩展性。
策略模式的本质:是算法分离,选择算法。
1.写一个抽象处理器来约束具体的实现

也可以定义成接口,定义成抽象类是因为有一些流程公共的方法可以放在抽象类中、
/**
 * 抽象类,用来约束具体的处理流程
 */
public abstract class AbstractHandler {
    abstract public String handle(String type);
}


2.写多个具体的实现(请假,合同)
/**
 * 具体的流程类
 */
@Component
@HandlerType("1")
public class AgreementProcessHandler extends AbstractHandler{
    @Override
     public String handle(String type) {
        System.out.printf("type"+type);
        return "处理合同流程success";
    }
}

首先每个处理器都必须添加到spring容器中,因此需要加上@Component注解,其次需
要加上一个自定义注解@HandlerType,用于标识该处理器对应哪个流程,最后就是继
承AbstractHandler,实现自己的业务逻辑。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface HandlerType {
    String value();
}
自定义注解和抽象处理器都很简单,那么如何将处理器注册到spring容器中呢?

具体思路是:

1、扫描指定包中标有@HandlerType的类;

2、将注解中的类型值作为key,对应的类作为value,保存在Map中;

3、以上面的map作为构造函数参数,初始化HandlerContext,将其注册到spring容器中;

我们将核心的功能封装在HandlerProcessor类中,完成上面的功能。

/**
 * 扫描所有有HandlerType的注解的类,放入HandlerContext
 * 将HandlerContext注册到spring中去
 */
@Component
public class HandlerProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        Map<String,Class> handleMap  = new HashMap<>();
        Set<Class<?>> classSet =  ClassScaner.scan("com.ding", HandlerType.class);
        for(Class clazz : classSet){
            HandlerType handlerType = (HandlerType) clazz.getAnnotation(HandlerType.class);
            handleMap.put(handlerType.value(),clazz);
        }
        HandlerContext handlerContext = new HandlerContext(handleMap);
        beanFactory.registerSingleton(HandlerContext.class.getName(),handlerContext);
    }
}
核心工作已经完成,现在看看HandlerContext如何获取对应的处理器:
SpringContextHolder:获取bean工具类

#getInstance 方法根据类型获取对应的class,然后根据class类型获取注册到spring中的bean。

最后请注意一点,HandlerProcessor和SpringContextHolder必须能被扫描到,或者通过@Bean的方式显式的注册,才能在项目启动时发挥作用。

<bean class="com.ding.utils.SpringContextHolder"></bean>
<context:component-scan base-package="com.ding.handler" />

/**
 * 上下文 用一个map来维护,获取所有有HandlerType的类
 */
public class HandlerContext {
    private Map<String,Class> classHandlerMap;

    public HandlerContext(Map<String, Class> classHandlerMap) {
        this.classHandlerMap = classHandlerMap;
    }

    public AbstractHandler getInstance(String type){
        Class clazz = classHandlerMap.get(type);
        if(clazz ==null ){
            throw  new IllegalArgumentException("not found handler for type"+type);
        }
        return (AbstractHandler) SpringContextHolder.getBean(clazz);
    }
}

调用方式


    /**
     * 测试策略模式
     */
    @SuppressWarnings("rawtypes")
    @RequestMapping("/testMode")
    @ResponseBody
    public Result testMode(String type){
        Result res = new Result();
        AbstractHandler handler = handlerContext.getInstance(type);
        handler.handle(type);
        return res;
    }

 

原文地址  http://www.54288.top/article/view.do?articleId=130

原文地址  http://www.54288.top/article/view.do?articleId=130

原文地址  http://www.54288.top/article/view.do?articleId=130

原文地址  http://www.54288.top/article/view.do?articleId=130

原文地址  http://www.54288.top/article/view.do?articleId=130

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值