策略模式

策略模式用于解决判断分支过多的问题,使代码变得简洁和优雅,

策略模式在多种方式在项目中落地,下面举例说明通过指定不同类型的订单使用策略模式执行不同的业务逻辑

文章参考自公众号:石杉的架构笔记

一.项目结构

 二.各个类的说明

  1.自定义注解

  //通过注解中的value值来表示不同的分支,从而执行不同的业务逻辑

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface HandlerType { String value();
}

  2.处理器相关

    -抽象处理器-定义子处理器要实现的行为

public abstract class AbstractHandler {

    public  abstract String handle(OrderDTO dto);
}

    -子处理器1-实现抽相关处理器的行为1

@HandlerType(value = "1")
@Component
public class NomalHandler extends AbstractHandler{
@Override
public String handle(OrderDTO dto) {
return "normal";
}
}

    -子处理器2-实现抽相关处理器的行为2

@HandlerType(value = "2")
@Component
public class GroupHandler extends AbstractHandler{
@Override
public String handle(OrderDTO dto) {
return "group";
}
}

    -处理器上下文-根据不同条件映射到不同的处理器

public class HandleContext {

    private Map<String,Class> handlerMap;

    public HandleContext(Map<String,Class> handlerMap){
this.handlerMap=handlerMap;
} public AbstractHandler getInstance(String type){
Class<? extends AbstractHandler> aClass = handlerMap.get(type);
if (aClass==null) {
throw new IllegalArgumentException();
}
return SpringContextUtil.getBean(aClass);
}
}

  3.处理器加载类-用于加载处理器上下文到spring的bean容器中,同时初始化数据

@Component
@SuppressWarnings("unchecked")
public class HandlerProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
Map<String, Class> handlerMap = new HashMap<>();
//获取指定报下的所有类
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
MetadataReaderFactory metaReader = new CachingMetadataReaderFactory();
List<Class<?>> list = new ArrayList();
try {
Resource[] resources = resolver.getResources("classpath*:designstrategy/demo/config/handler/*.class"); ClassLoader loader = ClassLoader.getSystemClassLoader();
for (Resource resource : resources) {
MetadataReader reader = metaReader.getMetadataReader(resource);
String className = reader.getClassMetadata().getClassName();
Class<?> clazz = loader.loadClass(className);
HandlerType annotation = clazz.getAnnotation(HandlerType.class);
// System.out.println("格式化前:"+clazz); class designstrategy.demo.config.handler.AbstractHandler
System.err.println("格式化后:" + ClassUtils.getQualifiedName(clazz));
//获取所有接口
ClassUtils.getAllInterfaces(clazz);
//判断是一个类是不是抽象类
boolean anAbstract = Modifier.isAbstract(clazz.getModifiers());
// System.err.println("判断一个类是不是抽象类:" + anAbstract);如果不是抽象类,添加到集合
if (!anAbstract) {
list.add(clazz);
}
}
System.out.println("集合" + list);
//将类添加到Map中
for (Class<?> aClass : list) {
Annotation[] annotations = aClass.getAnnotations();
// 这里有个坑 Annotation annotation = aClass.getAnnotation(HandlerType.class);获取到的annotation为null
for (Annotation annotation : annotations) {
if (annotation instanceof HandlerType) {
String value = ((HandlerType) annotation).value();
handlerMap.put(value, aClass);
System.out.println(value);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
HandleContext handleContext = new HandleContext(handlerMap);
//将上下文添加到spring bean容器中
configurableListableBeanFactory.registerSingleton(HandleContext.class.getName(), handleContext);
}
}

  4.工具类-用于获取spring 容器中的bean

@Component
public class SpringContextUtil implements ApplicationContextAware { private static ApplicationContext applicationContext; @Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringContextUtil.applicationContext = applicationContext;
} //获取applicationContext
public static ApplicationContext getApplicationContext() {
return applicationContext;
} //通过name获取 Bean.
public static Object getBean(String name) {
return getApplicationContext().getBean(name);
} //通过class获取Bean.
public static <T> T getBean(Class<T> clazz) {
return getApplicationContext().getBean(clazz);
} //通过name,以及Clazz返回指定的Bean
public static <T> T getBean(String name, Class<T> clazz) {
return getApplicationContext().getBean(name, clazz);
} }

  5.controller层

@RestController
@RequestMapping("/order")
public class OrderController { @Autowired
private OrderService orderService; @RequestMapping("/handle")
public String handle(OrderDTO dto){
String str=orderService.handle(dto);
System.out.println(str);
return str;
}
}

  6.service层

@Service
public class OrderServiceImpl implements OrderService{ @Autowired
private HandleContext handleContext; @Override
public String handle(OrderDTO dto) {
AbstractHandler handler = handleContext.getInstance(dto.getType());
return handler.handle(dto);
}
}

  7.实体 

@Data
public class OrderDTO {
/** 订单类型 */
private String type;
}

三.测试

启动项目:使用postman分别测试以下两个接口

接口一:localhost:8080/order/hander?type=1

返回结果:normal

接口二localhost:8080/order/hander?type=2

返回结果:group

代码地址:https://github.com/AlenYang123456/design-strategy

  

【策略模式】策略模式结合Spring实战Demo的更多相关文章

  1. 【责任链模式】责任链模式结合Spring实战Demo

    备注: 责任链与策略模式有很多相似之处,如都是行为型设计模式,都能够处理代码中的if-else逻辑 主要区别在于: 策略模式 封装了算法,通过上下文对象去接受客户端的数据,根据数据类型执行不同的算法 ...

  2. 《设计模式面试小炒》策略和工厂模式替代业务场景中复杂的ifelse

    <设计模式面试小炒>策略和工厂模式替代业务场景中复杂的ifelse 我是肥哥,一名不专业的面试官! 我是囧囧,一名积极找工作的小菜鸟! 囧囧表示:小白面试最怕的就是面试官问的知识点太笼统, ...

  3. 3.js模式-策略模式

    1. 策略模式 策略模式定义一系列的算法,把它们封装起来,并且可以互相替换. var strategies = { isNonEmpty: function(value,errMsg){ if(val ...

  4. 模板模式与策略模式/template模式与strategy模式/行为型模式

    模板模式 模版模式,又被称为模版方法模式,它可以将工作流程进行封装,并且对外提供了个性化的控制,但主流程外界不能修改,也就是说,模版方法模式中,将工作的主体架构规定好,具体类可以根据自己的需要,各自去 ...

  5. 命令模式 & 策略模式 & 模板方法

    一.策略模式 策略模式:封装易变化的算法,可互相替换. GoF<设计模式>中说道:定义一系列算法,把它们一个个封装起来,并且使它们可以相互替换.该模式使得算法可独立于它们的客户变化. 比如 ...

  6. Java设计模式(七)策略模式 模板模式

    (十三)策略模式 策略图案限定了多个封装算法,该算法可以相互替换包.法的客户.借用还有一位大神的样例. interface ICalculator{ public int calculate(Stri ...

  7. Springboot中实现策略模式+工厂模式

    策略模式和工厂模式相信大家都比较熟悉,但是大家有没有在springboot中实现策略和工厂模式? 具体策略模式和工厂模式的UML我就不给出来了,使用这个这两个模式主要是防止程序中出现大量的IF ELS ...

  8. 工厂模式&策略模式。

    抽象.封装,具体事情做得越多,越容易犯错误.这每个做过具体工作的人都深有体会,相反,官做得越高,说出的话越抽象越笼统,犯错误可能性就越少.好象我们从编程序中也能悟出人生道理.(百度百科) 不断抽象封装 ...

  9. 简单工厂模式&策略模式-简介与区别

    不得不说,这两种模式真的很像. 相似点:都用到了面向对象的继承.多态.抽象,都拥有相似的结构. 不同点:工厂模式仅提供具体的实例对象,怎么使用这个对象是client的自由,策略模式client可以通过 ...

随机推荐

  1. jquery通过live绑定toggle事件

    $("a[name=reply]").live("click",function(){ $(this).toggle( function () { var $c ...

  2. SpringMVC异步处理的 5 种方式

    作者:丁仪 来源:https://chengxuzhixin.com/blog/post/SpringMVC-yi-bu-chu-li-de-5-zhong-fang-shi.html 前段时间研究了 ...

  3. ubuntu上pyecharts V1版本环境搭建

    1 背景 今天想用pyecharts画图,在新的环境下使用pip安装之后发现,导入pyecharts模块一直失败,报错如下. 图 1 导入pyecharts错误图 请注意:我这里使用的python版本 ...

  4. NodeJs 入门到放弃 — 网络服务器(三)

    码文不易啊,转载请带上本文链接呀,感谢感谢 https://www.cnblogs.com/echoyya/p/14484454.html 目录 码文不易啊,转载请带上本文链接呀,感谢感谢 https ...

  5. rest framework Views

    基于类的意见 Django的基于类的意见是从旧式的观点颇受欢迎. - Reinout面包车里斯 REST框架提供了一个APIView类,它的子类Django的View类. APIView类是从正规不同 ...

  6. css盒布局-省份选择盘的实现

    1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="U ...

  7. 20184307 实验三 Socket编程技术

    实验三 Socket编程技术 学号 20184307 2019-2020-2 <Python程序设计>实验三报告 课程:<Python程序设计> 班级:1843 姓名:章森洋 ...

  8. Android Studio 安装及配置

    安装时的那些事 •相关链接 [1]:无需翻墙的链接 [2]:Android Studio 安装教程 •从安装到放弃??? 初次接触 Android,并知道了开发 Android APP 的软件--An ...

  9. PReact10.5.13源码理解

    React源码看过几次,每次都没有坚持下来,索性学习一下PReact部分,网上讲解源码的不少,但是基本已经过时,所以自己来梳理下 render.js部分 import { EMPTY_OBJ, EMP ...

  10. go的令牌桶实现库 go-rate

    关于我 我的博客|文章首发 go-rate是速率限制器库,基于 Token Bucket(令牌桶)算法实现. go-rate被用在LangTrend的生产中 用于遵守GitHub API速率限制. 速 ...