在 Spring Boot 中,如何干掉 if else
全栈架构社区
共 3267字,需浏览 7分钟
· 2021-11-23
AI全套:Python3+TensorFlow打造人脸识别智能小程序
最新人工智能资料-Google工程师亲授 Tensorflow-入门到进阶
黑马头条项目 - Java Springboot2.0(视频、资料、代码和讲义)14天完整版
看到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 {
@Override
public 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 {
//使用策略模式实现
@Autowired
private HandlerContext handlerContext;
@Override
public String orderHandler(OrderDTO dto) {
/*
* 1:使用if..else实现
* 2:使用策略模式实现
*/
AOrderTypeHandler instance = handlerContext.getInstance(dto.getType());
return instance.handler(dto);
}
}
HandlerContext和HandlerProccessor
/**
* 订单策略模式环境
* 这个类的注入由HandlerProccessor实现
*/
public class HandlerContext {
private Map handlerMap;
/**
* 构造传参不能直接使用注解扫入
*/
public HandlerContext(Map 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
*/
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
Map 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 getBeansWithAnnotation(ConfigurableListableBeanFactory beanFactory, Class manager, Class extends OrderTypeHandlerAnno> annotation, String code) throws BeansException {
if (ObjectUtils.isEmpty(code)) {
throw new RuntimeException("code is null ");
}
Collection 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 {
@Override
public String handler(OrderDTO dto) {
return "处理普通订单";
}
}
/**
* 团队订单处理
*/
@Component
@OrderTypeHandlerAnno(OrderTypeEnum.Group)
public class GroupOrderHandler extends AOrderTypeHandler {
@Override
public String handler(OrderDTO dto) {
return "处理团队订单";
}
}
/**
* 促销订单处理
*/
@Component
@OrderTypeHandlerAnno(OrderTypeEnum.Promotion)
public class PromotionOrderHandler extends AOrderTypeHandler {
@Override
public String handler(OrderDTO dto) {
return "处理促销订单";
}
}
4.0.0 org.springframework.boot spring-boot-starter-parent 2.2.1.RELEASE com.kayak study-design 0.0.1-SNAPSHOT study-design Demo project for Spring Boot 1.8 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test org.junit.vintage junit-vintage-engine org.springframework.boot spring-boot-maven-plugin " tab="innerlink" data-linktype="2" wah-hotarea="click" style="outline: 0px; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); cursor: pointer; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important;">controller
/**
* 策略模式
*/
@RestController
public class StrategyController {
@Resource(name = "orderServiceImpl")
private IOrderService orderService;
@GetMapping("/api/order")
@ResponseBody
public String orderSave(OrderDTO dto) {
String str = orderService.orderHandler(dto);
return "{\"status\":1,\"msg\":\"保存成功\",\"data\":\"" + str + "\"}";
}
}
pom.xml文档
"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.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.2.1.RELEASEversion>
<relativePath/>
parent>
<groupId>com.kayakgroupId>
<artifactId>study-designartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>study-designname>
<description>Demo project for Spring Bootdescription>
<properties>
<java.version>1.8java.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
<exclusions>
<exclusion>
<groupId>org.junit.vintagegroupId>
<artifactId>junit-vintage-engineartifactId>
exclusion>
exclusions>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
总结:
利用策略模式可以简化复杂的if else代码,方便维护,而利用自定义注解和自注册的方式,可以方便应对需求的变更。
全栈架构社区交流群
「全栈架构社区」建立了读者架构师交流群,大家可以添加小编微信进行加群。欢迎有想法、乐于分享的朋友们一起交流学习。
看完本文有收获?请转发分享给更多人
往期资源:
评论
有意思!一个关于 Spring 历史的在线小游戏
发现 Spring One 的官网上有个好玩的彩蛋,分享给大家!进到Spring One的官网,可以看到右下角有个类似马里奥游戏中的金币图标。点击该金币之后,会打开一个新的页面,进入下面这样一个名为:The History Of Spring 的在线小游戏你可以使用上下左右的方向键来控制Spring
公众号程序猿DD
1
什么是以太坊期货ETF?它们如何运作?
作者:Jagjit Singh,CoinTelegraph;编译:陶朱,金色财经一、以太坊期货 ETF 介绍以太坊期货 ETF 是追踪以太坊期货合约而非以太坊本身的投资基金。考虑一份承诺在未来某个时间以特定价格购买以太坊的合约。这些衍生品合约通过以太坊 (ETH) 期货交易所交易基金 (ETF) 进
区块链头条
0
字节面试:如何解决MQ消息积压问题?
面试题大全:www.javacn.siteMQ(Message Queue)消息积压问题指的是在消息队列中累积了大量未处理的消息,导致消息队列中的消息积压严重,超出系统处理能力,影响系统性能和稳定性的现象。1.消息积压是哪个环节的问题?MQ 执行有三大阶段:消息生产阶段。消息存储阶段。消息消费阶段。
Java中文社群
0
如何动手做出一个 CPU,很简单
将Python客栈设为“星标⭐”第一时间收到最新资讯来源:无聊的闪客纯手工打造一个 CPU 这个事儿。在电子专业的同学眼里,很容易。在计算机专业的同学眼里,稍稍有点复杂,有的专业课的实验课可能会带着同学做一个,或者用 Logisim 这样的仿真软件去模拟实现一个。在非计算机专业的同学眼里,就有点不敢
Python客栈
0
面试官:MySQL 上亿大表,如何深度优化?
来源:cnblogs.com/YangJiaXin/p/10828244.html背景分析测试实施索引优化后delete大表优化为小批量删除总结前段时间刚入职一家公司,就遇上这事!背景XX实例(一主一从)xxx告警中每天凌晨在报SLA报警,该报警的意思是存在一定的主从延迟(若在此时发生主从切换,需要
好好学java
0
分享几个前端中好玩且有用的开源工具,总有一个适合你!
点击上方 前端Q,关注公众号回复加群,加入前端Q技术交流群正所谓差生文具多,作为前端的我们,拥有几个合适的工具和网站可以很有效的提高我们的工具效率,还会有一些很有趣的网站可以在我们敲 bug 累了的时候供我们娱乐,接下来我就和大嘎分析一下我在用的一些工具和网站。聚合API该网站提供了大量的
前端Q
0
图解 transformer 中的自注意力机制
↓推荐关注↓本文将将介绍注意力的概念从何而来,它是如何工作的以及它的简单的实现。注意力机制在整个注意力过程中,模型会学习了三个权重:查询、键和值。查询、键和值的思想来源于信息检索系统。所以我们先理解数据库查询的思想。假设有一个数据库,里面有所有一些作家和他们的书籍信息。现在我想读一些Rabindra
Python学习与数据挖掘
0
AI智能视觉检测技术在工业级测量领域的创新应用--AMB Tube-Q导管数字化测量系统
技术背景在深度学习算法出来之前,对于视觉算法来说,大致可以分为以下5个步骤:特征感知,图像预处理,特征提取,特征筛选,推理预测与识别。早期的机器学习中,占优势的统计机器学习群体中,对特征是不大关心的。深度学习是机器学习技术的一个方面,由人工神经网络提供支持。深度学习技术的工作原理是教机器通过实例学习
机器视觉
0