# StrategyDemo **Repository Path**: eason93/StrategyDemo ## Basic Information - **Project Name**: StrategyDemo - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2019-05-27 - **Last Updated**: 2022-03-11 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## 策略模式 ### 1.介绍 策略模式定义了一系列的算法,并将每一个算法封装起来,使每个算法可以相互替代,使算法本身和使用算法的客户端分割开来,相互独立。 策略模式基于的一种**开闭原则** 开闭原则:     对于扩展是开放的(Open for extension)。这意味着模块的行为是可以扩展的。当应用的需求改变时,我们可以对模块进行扩展,使其具有满足那些改变的新行为。也就是说,我们可以改变模块的功能。     对于修改是关闭的(Closed for modification)。**对模块行为进行扩展时,不必改动模块的源代码或者二进制代码。** ### 2.理论实际 在很多过程中,一个代码块需要使用很多if-else来实现我们的现有逻辑。 如: ``` public BigDecimal quote(String type){ if ("第一种实现".equals(type)) { return this.firstImpl(); }else if ("第二种实现".equals(type)) { return this.secondmpl(); }else if("第三种实现".equals(type)){ return this.thirdImpl(); } return null; } ``` 虽然这个看上去不是很复杂,用if-else还能结构,但是如果当中的业务逻辑复杂的话那就会非常糟糕;而且如果当中需要添加一种逻辑的话那就需要改动很多的代码。 所以我们需要抽象出来一种模型来适应相应的变化。 下面我们就来详细了解策略模型在代码中的实践。 #### 2.1 架构图 本文基于的是以下的架构图: ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190527175647504.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3pycXN5aA==,size_16,color_FFFFFF,t_70) #### 2.2 策略模式核心 核心入口 ``` @RestController @RequestMapping("/test") public class TestController { @Autowired private MyContext myContext; @GetMapping("/{value}") public String test(@PathVariable("value") String value) { return myContext.getInstance(value).handler(); } } ``` 通过MyContext去获取到执行的相关信息。 MyContext的源码: ``` public class MyContext { Map map=new HashMap<>(); public MyContext(Map map) { this.map = map; } public MyHandler getInstance(String type){ Class clazz = map.get(type); if(StringUtils.isEmpty(clazz)){ throw new IllegalArgumentException("class of this type is null"); } return (MyHandler) BeanTools.getBean(clazz); } } ``` 核心模型:通过一个map对象存储相关的bean信息,map结构是<注解的type名字,bean的实际class> 然后通过读取map的名字就能获取相关的class #### 2.3 获取bean 上文说是通过map对象去获取bean的对象的,那map的bean对象是怎么来的呢? 这个的bean的对象是通过实现BeanFactoryPostProcessor(默认spring会扫描这个类的所有对象,执行方法postProcessBeanFactory(spring执行过程中的refreshContext中执行的)) ``` @Component public class HandlerProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException { Map map=new HashMap<>(); //classScanner是一个工具类,用来扫描所有在包下注解的实现 ClassScanner classScanner=new DefaultClassScanner(); classScanner.scanByAnno(Arrays.asList("com.example.demo.Service"), MyHandlerAnnotation.class).forEach( aClass -> { //获取注解的value值,然后放入map中作为key String value=((MyHandlerAnnotation)aClass.getAnnotation(MyHandlerAnnotation.class)).value(); map.put(value,aClass); } ); MyContext myContext=new MyContext(map); //把myContext注入到spring中,这样上面@AutoWired才能使用 configurableListableBeanFactory.registerSingleton(myContext.getClass().getName(),myContext); } } ``` 读取bean的方法:(实现BeanFactoryAware就能是spring初始化的时候把beanFactory记录下来) ``` @Component public class BeanTools implements BeanFactoryAware { private static BeanFactory beanFactory; @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { this.beanFactory=beanFactory; } public static Object getBean(Class name){ return beanFactory.getBean(name); } } ``` ### 2.3 其他代码 注解: ``` @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited public @interface MyHandlerAnnotation { String value(); } ``` 使用的接口(也可以使用抽象方法): ``` public interface MyHandler { public String handler(); } ``` 使用注解的实现类: ``` public class FirstHandlerImpl implements MyHandler { @Override public String handler() { return "FirstHandlerImpl"; } } ``` ### 遗留的问题 1. ClassScanner是一个开源项目还没有阅读人家的源码,只是扫了一眼,感觉是读取目录然后比对;具体还需要继续研究。 2. ClassScanner和ClassLoader的比较,看看有啥实现的共通和不同。 ### 参考 1. [ClassScan工具类](https://gitee.com/loolly/hutool) 2. [java通过名称获取实体bean](https://blog.csdn.net/hgg923/article/details/53908539) 3. **[在 Spring Boot 中,如何干掉 if else](https://mp.weixin.qq.com/s/yohiSiNPRyn0LydEiUrW9w)** 4. [策略模式](https://www.cnblogs.com/lewis0077/p/5133812.html)