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

使用鏈式風格構造對象

測試:

再添加策略添加實現類,啟用注解即可!

省去了工廠模式,直接用注解實現,避免修改工廠類,

這里貼一個我們之前項目的工廠類實現:

如果再添加策略還是會有輕微的改動!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM