springboot中使用自定义注解实现策略模式,去除工厂模式的switch或ifelse,实现新增策略代码零修改

springboot中使用自定义注解实现策略模式,去除工厂模式的switch或ifelse,实现新增策略代码零修改

树冢
2021-03-08 / 0 评论 / 49 阅读 / 正在检测是否收录...

整体思路就是通过注解在策略类上指定约定好的type,项目启动之后将所有有注解的type获取到,根据type存储,然后在业务中根据type获取对应的策略即可。本文已模拟订单业务进行演示,根据订单的type,需要不同的处理逻辑,比如,免费订单,半价订单等。

1.策略接口和实现

/**
 * 处理订单策略
 */
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("----处理打折订单----");
    }
}

2.自定义策略注解

@Target(ElementType.TYPE)  //作用在类上
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited  //子类可以继承此注解
public @interface HandlerOrderType {
    /**
     * 策略类型
     * @return
     */
    int value();
}

3.业务实体

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

4.核心功能实现

/**
 * 根据订单类型返回对应的处理策略
 */
@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);
        });
    }
}

5.业务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);
    }
}

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

7.测试

km0gqw1h.png
再添加策略添加实现类,启用注解即可!省去了工厂模式,直接用注解实现,避免修改工厂类,这里贴一个我们之前项目的工厂类实现:
km0grbpd.png

0

评论 (0)

取消
百大云