springboot中使用自定义注解实现策略模式,去除工厂模式的switch或ifelse,实现新增策略代码零修改
前言 思路与模拟业务
源码地址 https://gitee.com/houzheng1216/springboot
整体思路就是通过注解在策略类上指定约定好的type,项目启动之后将所有有注解的type获取到,根据type存储,然后在业务中根据type获取对应的策略即可
模拟订单业务,根据订单的type,需要不同的处理逻辑,比如,免费订单,半价订单等,下面是项目结构:
一 策略接口和实现
/**
* 处理订单策略
*/
public interface OrderStrategy { void handleOrder(Order order);
}
@Component
@HandlerOrderType(Order.FREE) //使用注解标明策略类型
public class FreeOrderStrategy implements OrderStrategy {
@Override
public void handleOrder(Order order) {
System.out.println("----处理免费订单----");
}
}
@Component
@HandlerOrderType(Order.HALF)
public class HalfOrderStrategy implements OrderStrategy {
@Override
public void handleOrder(Order order) {
System.out.println("----处理半价订单----");
}
}
@Component
@HandlerOrderType(Order.DISCOUT)
public class DiscoutOrderStrategy implements OrderStrategy {
@Override
public void handleOrder(Order order) {
System.out.println("----处理打折订单----");
}
}
二 自定义策略注解
@Target(ElementType.TYPE) //作用在类上
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited //子类可以继承此注解
public @interface HandlerOrderType {
/**
* 策略类型
* @return
*/
int value();
}
此处只能用基本类型或者String,约定的类型放在Order实体类里
三 业务实体
public class Order {
public static final int FREE=1; //免费订单
public static final int HALF=2; //半价订单
public static final int DISCOUT=3; //打折订单
private String name;
private Double price;
private Integer type;//订单类型
public static Order build(){
return new Order();
}
四 核心功能实现
主要就是这一块实现策略逻辑
/**
* 根据订单类型返回对应的处理策略
*/
@Component
public class HandlerOrderContext {
@Autowired
private ApplicationContext applicationContext;
//存放所有策略类Bean的map
public static Map<Integer, Class<OrderStrategy>> orderStrategyBeanMap= new HashMap<>(); public OrderStrategy getOrderStrategy(Integer type){
Class<OrderStrategy> strategyClass = orderStrategyBeanMap.get(type);
if(strategyClass==null) throw new IllegalArgumentException("没有对应的订单类型");
//从容器中获取对应的策略Bean
return applicationContext.getBean(strategyClass);
}
}
/**
* 策略核心功能,获取所有策略注解的类型
* 并将对应的class初始化到HandlerOrderContext中
*/
@Component
public class HandlerOrderProcessor implements ApplicationContextAware {
/**
* 获取所有的策略Beanclass 加入HandlerOrderContext属性中
* @param applicationContext
* @throws BeansException
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
//获取所有策略注解的Bean
Map<String, Object> orderStrategyMap = applicationContext.getBeansWithAnnotation(HandlerOrderType.class);
orderStrategyMap.forEach((k,v)->{
Class<OrderStrategy> orderStrategyClass = (Class<OrderStrategy>) v.getClass();
int type = orderStrategyClass.getAnnotation(HandlerOrderType.class).value();
//将class加入map中,type作为key
HandlerOrderContext.orderStrategyBeanMap.put(type,orderStrategyClass);
});
}
}
五 业务service使用
@Component
public class OrderServiceImpl implements OrderService {
@Autowired
HandlerOrderContext handlerOrderContext;
@Override
public void handleOrder(Order order) {
//使用策略处理订单
OrderStrategy orderStrategy = handlerOrderContext.getOrderStrategy(order.getType());
orderStrategy.handleOrder(order);
}
}
很简单,业务代码以后基本不用再修改,不管添加多少策略或者需求变更多少次
六 controller测试
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
OrderService orderService;
@GetMapping("/handler/{type}")
public void handleOrder(@PathVariable Integer type){
Order order = Order.build()
.add("name", "微信订单")
.add("price", 99.9)
.add("type", type);
orderService.handleOrder(order);
}
}
使用链式风格构造对象
测试:
再添加策略添加实现类,启用注解即可!
省去了工厂模式,直接用注解实现,避免修改工厂类,
这里贴一个我们之前项目的工厂类实现:
如果再添加策略还是会有轻微的改动!
springboot中使用自定义注解实现策略模式,去除工厂模式的switch或ifelse,实现新增策略代码零修改的更多相关文章
- Springboot中如何自定义注解以及使用2例
不说废话,直接进入正题: java自定义注解主要有3步:1.编写@interface接口2.编写@interface对应的处理方法进行处理3.调用处理方法 示例一:判断奇偶:比如有一个字段no要判断奇 ...
- springboot中的常用注解
springboot中的常用注解个人觉得springboor中常用的注解主要可以分为三种:放入容器型注解.从容器中取出型注解和功能型注解.其中的放入容器型和从容器中取出型就是我们平时所说的控制反转和依 ...
- springboot中的controller注解没有生效
springboot中的controller注解没有生效 , 启动的Application类没有在controller的父目录或同级目录
- Java中的GOF23(23中设计模式)--------- 工厂模式(Factory)
Java中的GOF23(23中设计模式)--------- 工厂模式(Factory) 在给大家介绍工厂模式之前,我想和大家聊聊面向对象的那点事,在这里,引入三个概念. 开闭原则(Open Close ...
- python 使用模板模式和工厂模式的混合设计开发各种邮件客户端发送邮件
1.使用模板模式和工厂模式的混合设计开发各种邮件客户端发送邮件. 2.模板模式的目的:能保证快速开发各种邮箱客户端,子类只需要重写模板类邮箱的抽象方法即可.之后再开发任何邮箱就只要加一个类,写3行代码 ...
- javascript模式 (3)——工厂模式和装饰模式
上节我们讲解了单例模式,这节我们将继续讲解工厂模式和迭代器模式 工厂模式: 工厂模式的目的是为了方便的创建对象(可以在不知道构造的情况下),通过静态方法来实现,在java或c#等静态编译语言中需要通过 ...
- 结合实例分析简单工厂模式&工厂方法模式&抽象工厂模式的区别
之前写过一篇关于工厂模式(Factory Pattern)的随笔,里面分析了简单工厂模式,但对于工厂方法和抽象工厂的分析较为简略.这里重新分析分析三者的区别,工厂模式是java设计模式中比较简单的一个 ...
- 简单工厂模式,工厂方法模式,抽象工厂模式,spring的狂想
菜鸟D在项目中遇见一个比较纠结的高耦合,所以就想办法来解耦.情况是这样的:系统通过用户选择treeview控件的节点判断调用不同的处理,这些处理中某些东西又是类似的.同事的建议是采用简单工厂,耦合就耦 ...
- Java设计模式之(工厂模式)--简单工厂模式--工厂方法模式--抽象工厂模式
工厂模式: 工厂模式可以分为三类: 1)简单工厂模式(Simple Factory) 2)工厂方法模式(Factory Method) 3)抽象工厂模式(Abstract Factory) 简单工厂模 ...
随机推荐
- CSV 文件的存取
CSV 文件介绍 CSV(Comma-Separated Values),中文通常叫做逗号分割值.CSV文件由任意数目的记录(行)组成,每条记录由一些字段(列)组成,字段之间通常以逗号分割,当然也可以 ...
- matlab写入excel数据
使用xlswrite 可以help xlswrite查看用法 xlswrite(filename,A)xlswrite(filename,A,sheet)xlswrite(filename,A,xlR ...
- Vi的三种模式及其指令
第一部分:一般指令模式可用按键说明,光标移动,复制粘贴.搜索替代 移动光标的方法: 移动光标的方法 h或(左箭头) 光标向左移动一个字符 j或(下箭头) 光标向下移动一个字符 k或(上箭头) 光标向上 ...
- 解决vue中element组件样式修改无效
vue中element组件样式修改无效 <style> .detail{ .el-input__inner { height: 48px; } } </style> 直接写st ...
- Spring中使用注解 @Scheduled执行定时任务
注解@Scheduled 使用方式 注解@Scheduled 可以作为一个触发源添加到一个方法中,例如,以下的方法将以一个固定延迟时间5秒钟调用一次执行,这个周期是以上一个调用任务的完成时间为基准,在 ...
- 原生javascript 元素依次掉落及上升
一.实现原理: ① 通过onoff开关,判断元素是往下走 还是往上走,并在每次清除定时器后,把onoff 设为 !onoff,以便下次点击做判断 ②move函数的运用 二.代码 <!DOCTYP ...
- shell学习-常用语句
为什么使用shell 可以快速.简单的完成编程,实现自己的想法.Shell非常适合编写小的工具,因为小工具更强调的是易于配置.维护.移植等,而不是执行效率. 当自己的想法确实有必要进行优化,有必要让它 ...
- Vue中使用js-xlsx导出Data数据到Excel
需要引入的第三方JS有:export.js.xlsx.extendscript.js.xlsx.full.min.js JS太大不贴出来,放一个可下载百度云连接:https://pan.baidu.c ...
- dp-完全背包
( 推荐 : http://blog.csdn.net/insistgogo/article/details/11081025 ) 问题描述 : 已知一个容量为 V 的背包 和 N 件物品 , 第 ...
- eclipse android ndk开发遇到的问题.
1. error:parameter name omitted 用javah生成的.h文件中,方法是没有指定形参的,实现的时候需要我们在实现的方法定义中加上形参. 2. 'NewStringUTF' ...