spring+策略模式

需求: 這裏虛擬一個業務需求,讓你們容易理解。假設有一個訂單系統,裏面的一個功能是根據訂單的不一樣類型做出不一樣的處理。java

 

1. 常規代碼實現 web

1.1 實體類spring

import lombok.Data; import java.math.BigDecimal; @Data public class OrderDTO { private String code; private BigDecimal price; /** * 訂單類型 * 1: 普通訂單 * 2: 團購訂單 * 3: 促銷訂單 */
    private String type; }

 

1.2  接口類app

import qinfeng.zheng.strategy.dto.OrderDTO; public interface IOrderService { /** * 根據訂單類型作出相應的處理 * * @param orderDTO * @return
     */ String handle(OrderDTO orderDTO); }

 

1.3 接口實現 ide

import org.springframework.stereotype.Service; import qinfeng.zheng.strategy.dto.OrderDTO; import qinfeng.zheng.strategy.service.IOrderService; @Service public class V1OrderServiceImpl implements IOrderService { @Override public String handle(OrderDTO orderDTO) { String type = orderDTO.getType(); if (type.equals("1")) { return "處理普通訂單成功"; } if (type.equals("2")) { return "處理團購訂單成功"; } if (type.equals("3")) { return "處理促銷訂單成功"; } return "訂單類型不存在"; } }

 

1.4 結論post

  不用說, 這代碼 很low. 測試

 

2. 使用策略模式實現此功能this

   策略模式的關鍵就是一個抽象處理類,配上一個持有這個抽象處理類實例的context. 下面是代碼的具體的實現 spa

 

2.1 抽象類3d

import qinfeng.zheng.strategy.dto.OrderDTO; public abstract class AbsHandler { abstract public String handle(OrderDTO orderDTO); }

 

2.2 具體實現類

import org.springframework.stereotype.Component; import qinfeng.zheng.strategy.anno.HandlerType; import qinfeng.zheng.strategy.dto.OrderDTO; @Component @HandlerType("1") public class NormalHandler extends AbsHandler { @Override public String handle(OrderDTO orderDTO) { return "處理普通訂單"; } }
import org.springframework.stereotype.Component; import qinfeng.zheng.strategy.anno.HandlerType; import qinfeng.zheng.strategy.dto.OrderDTO; @Component @HandlerType("2") public class GroupHandler extends AbsHandler { @Override public String handle(OrderDTO orderDTO) { return "處理團購訂單"; } }
import org.springframework.stereotype.Component; import qinfeng.zheng.strategy.anno.HandlerType; import qinfeng.zheng.strategy.dto.OrderDTO; @Component @HandlerType("3") public class PromotionHandler extends AbsHandler { @Override public String handle(OrderDTO orderDTO) { return "處理促銷訂單"; } }

2.3 context類

public class HandlerContext { private Map<String, Class> handlerMap; public HandlerContext(Map<String, Class> handlerMap) { this.handlerMap = handlerMap; } public AbsHandler getInstance(String type) throws Exception { Class aClass = handlerMap.get(type); if (aClass == null) { throw new IllegalArgumentException("not found handler type :" + type); } return (AbsHandler) aClass.newInstance(); } }

 

2.3 自定義註解類

import java.lang.annotation.*; @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface HandlerType { String value(); }

 

2.4 自定義BeanFactory後置處理類,將HandlerContext註冊到spring容器中

import cn.hutool.core.lang.ClassScanner; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.stereotype.Component; import qinfeng.zheng.strategy.anno.HandlerType; import qinfeng.zheng.strategy.context.HandlerContext; import java.util.HashMap; import java.util.Map; @Component public class HandlerProcessor implements BeanFactoryPostProcessor { private static final String HANDLE_PACKAGE = "qinfeng.zheng.strategy"; /** * 掃描@HandlerType註解,初始化HandlerContext, 並將其註冊到spring容器中 * @param beanFactory bean工廠呀...... * @throws BeansException */ @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { Map<String, Class> handlerMap = new HashMap<>(); ClassScanner.scanPackageByAnnotation(HANDLE_PACKAGE,HandlerType.class).forEach(aClass -> { String value = aClass.getAnnotation(HandlerType.class).value(); handlerMap.put(value, aClass); }); // 初始化HandlerContext
        HandlerContext handlerContext = new HandlerContext(handlerMap); // 手動將HandlerContext註冊到spring容器中 beanFactory.registerSingleton(HandlerContext.class.getName(), handlerContext); } }

 

2.4 修改IOrderService接口實現 

@Service public class V2OrderServiceImpl implements IOrderService {  @Autowired private HandlerContext handlerContext; @Transactional @Override public String handle(OrderDTO orderDTO) throws Exception { AbsHandler handler = handlerContext.getInstance(orderDTO.getType()); return handler.handle(orderDTO); } }

 

2.5 寫個controller測試一下

import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import qinfeng.zheng.strategy.dto.OrderDTO; import qinfeng.zheng.strategy.service.IOrderService; @RestController public class OrderController { /** * @Autowired自定根據 v2OrderServiceImpl 名稱 適配 V2OrderServiceImpl這個實現類 */ @Autowired private IOrderService v2OrderServiceImpl; @GetMapping("/handle") public String handler(OrderDTO orderDTO) throws Exception { return v2OrderServiceImpl.handle(orderDTO); } }

 

好, 代碼寫完了,使用策略模式以後,代碼的擴展性確實加強,若訂單類型發生改變,只需添加AbsHandler的實現類便可,其它都不須要變。

可是,我以爲這代碼並很差呀, 這樣操做,實現策略模式的代碼太多了。 其二,我使用了 aClass.newInstance()反射方式建立一個具體的Handler對象,這兒並無使用spring的代理功能,因此若是在AbsHandler#handle方法上添加事務,是不會生效的,只能在V2OrderServiceImpl#handle方法添加事務。

不過這個示例也讓我真實體驗了一把 BeanFactoryPostProcessor 這個接口的功能, 之後若是有須要手動註冊bean的場景,能夠考慮使用這個接口,可是這個接口的主要功能並不註冊bean, 而是修改管理bean工廠內全部的beandefinition(未實例化)數據,而且爲所欲爲的修改屬性。 

 

 

此外,ClassScanner這個類使用hutool類庫。

以上示例代碼大多來自「java那些事兒」

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息