希望长大对我而言,是可以做更多想做的事,而不是被迫做更多不想做的事...... 首页 使用策略模式干掉大片的 if else 丁D 学无止境 2019-09-20 16:53 51422已阅读 策略模式 摘要本文介绍如何使用策略模式来消除if else。 **需求** ```js 这里虚拟一个业务需求,让大家容易理解。假设有一个OA系统,里面的一个功能根据不 同的流程做不同的处理,比如有合同流程,请假流程,印章申请流程,出差申请。外出流程,报销流程等等很多。 传统实现 根据类型写一堆的if else: public String handle(Process process){ if(process.type="1"){//请假} else if(process.type="2"){//合同} .... else{} } 这样就会导致这个class/method很庞大,维护性很差。 ``` **使用策略模式实现** ```js 策略模式的重心:是如何实现算法,而是如何组织,调用算法,让程序更加灵活,具有更 好的可维护性和扩展性。 策略模式的本质:是算法分离,选择算法。 ``` ```js 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(); } ``` ```js 自定义注解和抽象处理器都很简单,那么如何将处理器注册到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 handleMap = new HashMap<>(); Set> 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); } } ``` ```js 核心工作已经完成,现在看看HandlerContext如何获取对应的处理器: SpringContextHolder:获取bean工具类 #getInstance 方法根据类型获取对应的class,然后根据class类型获取注册到spring中的bean。 最后请注意一点,HandlerProcessor和SpringContextHolder必须能被扫描到,或者通过@Bean的方式显式的注册,才能在项目启动时发挥作用。 /** * 上下文 用一个map来维护,获取所有有HandlerType的类 */ public class HandlerContext { private Map classHandlerMap; public HandlerContext(Map 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); } } ``` **调用方式** ```js /** * 测试策略模式 */ @SuppressWarnings("rawtypes") @RequestMapping("/testMode") @ResponseBody public Result testMode(String type){ Result res = new Result(); AbstractHandler handler = handlerContext.getInstance(type); handler.handle(type); return res; } ``` 后续补充 讲的不错 https://zhuanlan.zhihu.com/p/91667659 [参考 如何干掉 Spring Boot 中大片的 if else?](https://mp.weixin.qq.com/s/sa_MMAzYg6jpy9s_rtvcCQ) 很赞哦! (107) 上一篇:Elasticsearch父子关系 下一篇:Elasticsearch6.3.2之x-pack 目录 点击排行 Elasticsearch6.3.2之x-pack redis哨兵 2019-07-09 22:05 Redis+Twemproxy+HAProxy+Keepalived 2019-07-12 17:20 GC优化策略和相关实践案例 2019-10-10 10:54 JVM垃圾回收器 2019-10-10 10:23 标签云 Java Spring MVC Mybatis Ansible Elasticsearch Redis Hive Docker Kubernetes RocketMQ Jenkins Nginx 友情链接 郑晓博客 佛布朗斯基 凉风有信 MarkHoo's Blog 冰洛博客 南实博客 Rui | 丁D Java研发工程师 生活可以用「没办法」三个字概括。但别人的没办法是「腿长,没办法」、「长得好看,没办法」、「有才华,没办法」。而你的没办法,是真的没办法。 请作者喝咖啡