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); } }
使用链式风格构造对象
测试:
再添加策略添加实现类,启用注解即可!
省去了工厂模式,直接用注解实现,避免修改工厂类,
这里贴一个我们之前项目的工厂类实现:
如果再添加策略还是会有轻微的改动!