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);
    }
}

使用链式风格构造对象

测试:

再添加策略添加实现类,启用注解即可!

省去了工厂模式,直接用注解实现,避免修改工厂类,

这里贴一个我们之前项目的工厂类实现:

如果再添加策略还是会有轻微的改动!

posted @ 2019-05-23 13:54  侯小厨  阅读(5891)  评论(0编辑  收藏  举报
Fork me on Gitee