设计模式之策略模式应用实例(Spring Boot 如何干掉 if else)

需求

这里虚拟一个业务需求,让大家容易理解。假设有一个订单系统,里面的一个功能是根据订单的不同类型作出不同的处理。

订单实体:

设计模式之策略模式应用实例(Spring Boot 如何干掉 if else)

service接口:

设计模式之策略模式应用实例(Spring Boot 如何干掉 if else)

传统实现

根据订单类型写一堆的if else:

设计模式之策略模式应用实例(Spring Boot 如何干掉 if else)

策略模式实现

利用策略模式,只需要两行即可实现业务逻辑:

设计模式之策略模式应用实例(Spring Boot 如何干掉 if else)

可以看到上面的方法中注入了HandlerContext,这是一个处理器上下文,用来保存不同的业务处理器,具体在下文会讲解。我们从中获取一个抽象的处理器AbstractHandler,调用其方法实现业务逻辑。

现在可以了解到,我们主要的业务逻辑是在处理器中实现的,因此有多少个订单类型,就对应有多少个处理器。以后需求变化,增加了订单类型,只需要添加相应的处理器就可以,上述OrderServiceV2Impl完全不需改动。

我们先看看业务处理器的写法:

设计模式之策略模式应用实例(Spring Boot 如何干掉 if else)

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

自定义注解 @HandlerType:

设计模式之策略模式应用实例(Spring Boot 如何干掉 if else)

抽象处理器 AbstractHandler:

设计模式之策略模式应用实例(Spring Boot 如何干掉 if else)

自定义注解和抽象处理器都很简单,那么如何将处理器注册到spring容器中呢?

具体思路是:

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

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

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

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

HandlerProcessor:

设计模式之策略模式应用实例(Spring Boot 如何干掉 if else)

ClassScaner:扫描工具类源码

HandlerProcessor 需要实现BeanFactoryPostProcessor,在spring处理bean前,将自定义的bean注册到容器中。

核心工作已经完成,现在看看HandlerContext如何获取对应的处理器:

HandlerContext:

设计模式之策略模式应用实例(Spring Boot 如何干掉 if else)

BeanTool:获取bean工具类

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

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

总结

利用策略模式可以简化繁杂的if else代码,方便维护,而利用自定义注解和自注册的方式,可以方便应对需求的变更。本文只是提供一个大致的思路,还有很多细节可以灵活变化,例如使用枚举类型、或者静态常量,作为订单的类型,相信你能想到更多更好的方法。

Original: https://www.cnblogs.com/mr-wuxiansheng/p/14459421.html
Author: Mr_伍先生
Title: 设计模式之策略模式应用实例(Spring Boot 如何干掉 if else)

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/541964/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Core Java 总结(字符和字符串类问题)

    所有代码均在本地编译运行测试,环境为 Windows7 32位机器 + eclipse Mars.2 Release (4.5.2) 2016-10-17 整理 字符,字符串类问题…

    Java 2023年5月29日
    089
  • 二. 手写SpringMVC框架

    1 新建DispatcherServlet 1.2 在src目录下,新建applicationContext.xml 1.3 在 Dispatcher S ervlet 的构造方法…

    Java 2023年6月16日
    055
  • 将vue项目部署到服务器并通过外网访问的三种方式(springboot中static/nginx)

    一.将vue项目打包后生成的dist目录下的文件复制到springboot项目里面 前端vue项目先通过npm run build生成dist目录 2.将dist中目录文件放入sp…

    Java 2023年6月5日
    098
  • mybatis-plus代码生成器2.0

    要在springboot项目下使用! 相关依赖 org.springframework.boot spring-boot-starter org.springframework.b…

    Java 2023年6月9日
    099
  • Java并发编程(一)JUC同步类

    JUC 是学习 Java 并发编程的小伙伴不可避免的一个 pkg,JUC提供了对并发编程的底层支持,比如我们熟悉的线程池、MQ、线程同步… 都有JUC的影子,下面我们一…

    Java 2023年6月9日
    081
  • 【源码】按照自己的思路研究Spring AOP源码 ①

    一个例子 从@EnableAspectJAutoProxy注解入手 什么时候会创建代理对象? 方法执行时怎么实现拦截的? 总结 问题 参考 一个例子 // 定义一个切面 packa…

    Java 2023年6月8日
    098
  • 实现邮箱发送验证码功能

    实现注册和忘记密码界面的邮箱发送验证码功能 邮箱验证步骤 本文使用了redis数据库做验证码的缓存,不想用redis数据库也可以直接将验证码放入mysql中,设置验证码有效期即可。…

    Java 2023年6月14日
    0102
  • javaweb获取客户端真实ip

          public static String getClientIP(HttpServletRequ…

    Java 2023年6月8日
    072
  • 用antlr的grammar获得java ast

    anttlr的代码样例:https://github.com/antlr/grammars-v4.git 很早之前就想基于java的语法树做一些事情,今天再次弄来看看。 基于ant…

    Java 2023年5月29日
    088
  • SpringBoot集成beetl模板开发

    1、添加maven依赖 <dependency> <groupId>com.ibeetlgroupId> <artifactId>beet…

    Java 2023年6月7日
    069
  • java httpclient简单使用

    httpClient 官网 https://hc.apache.org/index.html https://hc.apache.org/httpcomponents-client…

    Java 2023年5月29日
    079
  • java list的六种赋值方式

    java;gutter:true;public static void main(String[] args) { //第一种赋值 List list1 = Arrays.asLi…

    Java 2023年5月29日
    0108
  • 记一次dump文件分析历程

    一、背景 今天下午,正酣畅淋漓的搬砖,突然运维同事在群里通知,核心服务某个节点内存异常,服务假死。神经一下子紧张起来,赶紧跑到运维那边观察现象。 观察的结果是服务内存溢出,该服务是…

    Java 2023年6月5日
    0112
  • slf4j、log4j2及logback使用

    slf4j、log4j2及logback使用 1、问题来源 之前看过关于slf4j、log4j2及logback的介绍,slf4j是门面,log4j2及logback是具体实现,仅…

    Java 2023年6月15日
    0110
  • java和spring 线程池总结

    线程的使用在java中占有极其重要的地位,在jdk1.4极其之前的jdk版本中,关于线程池的使用是极其简陋的。在jdk1.5之后这一情况有了很大的改观。Jdk1.5之后加入了jav…

    Java 2023年5月29日
    075
  • leetcode 1110. Delete Nodes And Return Forest 删点成林(中等)

    一、题目大意 给出二叉树的根节点 root,树上每个节点都有一个不同的值。 如果节点值在 to_delete 中出现,我们就把该节点从树上删去,最后得到一个森林(一些不相交的树构成…

    Java 2023年6月14日
    093
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球