原文链接:blog.csdn.net/hncu1306602liuqiang

看到crossover Jie的文章《利用策略模式优化过多if else 代码》后受到启发,可以利用策略模式简化过多的if else代码。

需求

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

项目结构

订单实体

/*** 订单实体*/
public class OrderDTO {private String code;private BigDecimal price;/** 订单类型:* 1:普通订单* 2:团购订单* 3:促销订单*/private String type;
//getter,setter自己实现
}

service接口

/*** 订单处理*/
public interface IOrderService {/*** 根据订单的不同类型做出不同的处理** @param dto 订单实体* @return 为了简单,返回字符串*/String orderHandler(OrderDTO dto);}
//实现类1
@Component
public class OrderServiceImpl implements IOrderService {@Overridepublic String orderHandler(OrderDTO dto) {if ("1".equals(dto.getType())) {//普通订单处理} else if ("2".equals(dto.getType())) {//团购订单处理} else if ("3".equals(dto.getType())) {//促销订单处理}//未来订单类型增加}}
//实现类二
@Component
public class OrderServiceImpl implements IOrderService {//使用策略模式实现@Autowiredprivate HandlerContext handlerContext;@Overridepublic String orderHandler(OrderDTO dto) {/** 1:使用if..else实现* 2:使用策略模式实现*/AOrderTypeHandler instance = handlerContext.getInstance(dto.getType());return instance.handler(dto);}}

利用策略模式只需要2行代码就可以搞定(也可以用工厂)

HandlerContext和HandlerProccessor
/*** 订单策略模式环境* 这个类的注入由HandlerProccessor实现*/
public class HandlerContext {private Map<String, AOrderTypeHandler> handlerMap;/*** 构造传参不能直接使用注解扫入*/public HandlerContext(Map<String, AOrderTypeHandler> handlerMap) {this.handlerMap = handlerMap;}/*** 获得实例** @param type* @return*/public AOrderTypeHandler getInstance(String type) {if (type == null) {throw new IllegalArgumentException("type参数不能为空");}AOrderTypeHandler clazz = handlerMap.get(type);if (clazz == null) {throw new IllegalArgumentException("该类型没有在枚举OrderTypeHandlerAnno中定义,请定义:" + type);}return clazz;}}
/*** 策略模式,处理type与实现类的映射关系*/
@Component
public class HandlerProccessor implements BeanFactoryPostProcessor {/*** 扫描@OrderTypeHandlerAnno注解,初始化HandlerContext,将其注册到spring容器** @param beanFactory bean工厂* @throws BeansException*/@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {Map<String, AOrderTypeHandler> handlerMap = new HashMap<>();for (OrderTypeEnum temp : OrderTypeEnum.values()) {AOrderTypeHandler beanInstacle = getBeansWithAnnotation(beanFactory, AOrderTypeHandler.class, OrderTypeHandlerAnno.class, temp.getCode());handlerMap.put(temp.getCode(), beanInstacle);}HandlerContext context = new HandlerContext(handlerMap);//单例注入beanFactory.registerSingleton(HandlerContext.class.getName(), context);}/** 通过父类+注解找到实体类*/private <T> T getBeansWithAnnotation(ConfigurableListableBeanFactory beanFactory, Class<T> manager, Class<? extends OrderTypeHandlerAnno> annotation, String code) throws BeansException {if (ObjectUtils.isEmpty(code)) {throw new RuntimeException("code is null ");}Collection<T> tCollection = beanFactory.getBeansOfType(manager).values();for (T t : tCollection) {OrderTypeHandlerAnno orderTypeHandlerAnno = t.getClass().getAnnotation(annotation);if (ObjectUtils.isEmpty(orderTypeHandlerAnno)) {throw new RuntimeException("该注解没有写入值 :" + code);}//注解值是否与code相等if (code.equals(orderTypeHandlerAnno.value().getCode())) {return t;}}throw new RuntimeException("通过code没有找到该注解对应的实体类 :" + code);}}

父抽象类+注解+枚举

/*** 订单类型处理定义* 使用抽象类,那么子类就只有一个继承了*/
public abstract class AOrderTypeHandler {/*** 一个订单类型做一件事** @param dto 订单实体* @return 为了简单,返回字符串*/abstract public String handler(OrderDTO dto);}/*** 订单类型注解* 使用方式:* 1:普通订单 @OrderTypeHandlerAnno("1")* 2:团购订单 @OrderTypeHandlerAnno("2")* 3:促销订单 @OrderTypeHandlerAnno("3")*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface OrderTypeHandlerAnno {OrderTypeEnum value();}/*** 订单类型枚举*/
public enum OrderTypeEnum {Normal("1", "普通"),Group("2", "团队"),Promotion("3", "促销");private String code;    //代码private String name;    //名称,描述OrderTypeEnum(String code, String name) {this.code = code;this.name = name;}public String getCode() {return code;}public void setCode(String code) {this.code = code;}public String getName() {return name;}public void setName(String name) {this.name = name;}/*** 根据code属性获取name属性** @param code* @return*/public static String getNameByCode(String code) {for (OrderTypeEnum temp : OrderTypeEnum.values()) {if (temp.getCode().equals(code)) {return temp.getName();}}return null;}}

业务人员实现类

//业务代码
/*** 普通订单处理*/
@Component
@OrderTypeHandlerAnno(OrderTypeEnum.Normal)
public class NormalOrderHandler extends AOrderTypeHandler {@Overridepublic String handler(OrderDTO dto) {return "处理普通订单";}}/*** 团队订单处理*/
@Component
@OrderTypeHandlerAnno(OrderTypeEnum.Group)
public class GroupOrderHandler extends AOrderTypeHandler {@Overridepublic String handler(OrderDTO dto) {return "处理团队订单";}}/*** 促销订单处理*/
@Component
@OrderTypeHandlerAnno(OrderTypeEnum.Promotion)
public class PromotionOrderHandler extends AOrderTypeHandler {@Overridepublic String handler(OrderDTO dto) {return "处理促销订单";}}

测试结果(使用chrome浏览器测试结果)

如果类型不存在

controller/*** 策略模式*/
@RestController
public class StrategyController {@Resource(name = "orderServiceImpl")private IOrderService orderService;@GetMapping("/api/order")@ResponseBodypublic String orderSave(OrderDTO dto) {String str = orderService.orderHandler(dto);return "{\"status\":1,\"msg\":\"保存成功\",\"data\":\"" + str + "\"}";}}
pom.xml文档<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.2.1.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.kayak</groupId><artifactId>study-design</artifactId><version>0.0.1-SNAPSHOT</version><name>study-design</name><description>Demo project for Spring Boot</description><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope><exclusions><exclusion><groupId>org.junit.vintage</groupId><artifactId>junit-vintage-engine</artifactId></exclusion></exclusions></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

总结:

利用策略模式可以简化复杂的if else代码,方便维护,而利用自定义注解和自注册的方式,可以方便应对需求的变更。

在 Spring Boot 中,如何干掉 if else相关推荐

  1. Spring Boot中如何干掉过多的if else!

    你关注的就是我关心的! 需求 这里虚拟一个业务需求,让大家容易理解.假设有一个订单系统,里面的一个功能是根据订单的不同类型作出不同的处理. 订单实体: service接口: 传统实现 根据订单类型写一 ...

  2. Spring Boot中如何干掉if else

    2019独角兽企业重金招聘Python工程师标准>>> 需求 这里虚拟一个业务需求,让大家容易理解.假设有一个订单系统,里面的一个功能是根据订单的不同类型作出不同的处理. 如果想学习 ...

  3. Spring Boot 中使用@Async实现异步调用,加速任务执行!

    欢迎关注方志朋的博客,回复"666"获面试宝典 什么是"异步调用"?"异步调用"对应的是"同步调用",同步调用指程序按照 ...

  4. 再谈Spring Boot中的乱码和编码问题

    编码算不上一个大问题,即使你什么都不管,也有很大的可能你不会遇到任何问题,因为大部分框架都有默认的编码配置,有很多是UTF-8,那么遇到中文乱码的机会很低,所以很多人也忽视了. Spring系列产品大 ...

  5. 【spring boot2】第8篇:spring boot 中的 servlet 容器及如何使用war包部署

    嵌入式 servlet 容器 在 spring boot 之前的web开发,我们都是把我们的应用部署到 Tomcat 等servelt容器,这些容器一般都会在我们的应用服务器上安装好环境,但是 spr ...

  6. Spring Boot 中使用 MongoDB 增删改查

    本文快速入门,MongoDB 结合SpringBoot starter-data-mongodb 进行增删改查 1.什么是MongoDB ? MongoDB 是由C++语言编写的,是一个基于分布式文件 ...

  7. 徒手解密 Spring Boot 中的 Starter自动化配置黑魔法

    我们使用 Spring Boot,基本上都是沉醉在它 Stater 的方便之中.Starter 为我们带来了众多的自动化配置,有了这些自动化配置,我们可以不费吹灰之力就能搭建一个生产级开发环境,有的小 ...

  8. Maven中的profile和spring boot中的profile进行结合

    2019独角兽企业重金招聘Python工程师标准>>> 有一些应用,采用了spring boot和spring boot profile.然后想把maven 中的profile和sp ...

  9. Spring Boot中使用JavaMailSender发送邮件

    相信使用过Spring的众多开发者都知道Spring提供了非常好用的JavaMailSender接口实现邮件发送.在Spring Boot的Starter模块中也为此提供了自动化配置.下面通过实例看看 ...

  10. Spring Boot中Web应用的统一异常处理

    为什么80%的码农都做不了架构师?>>>    我们在做Web应用的时候,请求处理过程中发生错误是非常常见的情况.Spring Boot提供了一个默认的映射:/error,当处理中抛 ...

最新文章

  1. LeetCode简单题之检查是否区域内所有整数都被覆盖
  2. Linux echo详解
  3. css3 text-shadow 为网页字体添加阴影
  4. Linux 入门学习-LINUX基本认识及常用命令
  5. DSP学习 -- Visual Studio 操作
  6. Tensorflow实例3: 验证码图片的识别训练,每张图片有4个字母
  7. MySQL集群搭建——主备模式
  8. 乐播投延迟很高_大屏也要高刷新!华为4K@120智慧屏初体验,屏幕软件都够硬
  9. JavaScript 判断浏览器类型
  10. datagridview 绑定list 不能刷新界面_人人都可写代码-H5零基础编程-首页界面实操06...
  11. python multiprocessing 批量下载图片+tqdm
  12. redis mysql 事务_Mysql与Redis事务
  13. npm配置镜像、设置代理
  14. vdbench(一)
  15. linux怎么设置文件访问权限,Linux文件和目录访问权限设置
  16. 从Facebook更名Meta看元宇宙||亚太元宇宙新纪元峰会正式启动
  17. 老罗的工匠精神是不是有唯一性
  18. keil软件仿真逻辑分析仪出现了Unknown Signal
  19. while(1)语句
  20. 数组排序sort()。升序还是降序

热门文章

  1. 协议模型的最底层是_CAN通信协议栈(二) 之对ISO11898-1的理解
  2. 执行前端测试的必要性
  3. 硬件基础:电阻作用及产品应用
  4. TensorFlow中的Fashion MNIST图像识别实战
  5. 第1关:学习-用循环和数组实现输入某年某月某日,判断这一天一年的第几天
  6. 图论500题 ---- (枚举+并查集)求图上路径权值差值最小 HDU find the most comfortable road
  7. mysql的ab测试工具_轻量级性能测试工具ab / wrk / locust 分析 对比
  8. 【数学专题】莫比乌斯反演与积性函数
  9. linux2.0版本发布时间,Ubuntu 20.04 LTS发布时间表公布 4月23日放出最终稳定版
  10. java开发中用矩阵图吗_Java中的矩阵使用