在公司負責的就是訂單取消業務,老系統中各類類型訂單取消都是經過if else 判斷不一樣的訂單類型進行不一樣的邏輯。在經歷老系統的折磨和產品需求的不斷變動,決定進行一次大的重構:消滅 if else。java
接下來就向你們介紹下是如何消滅 if else。git
@Service public class CancelOrderService { public void process(OrderDTO orderDTO) { int serviceType = orderDTO.getServiceType(); if (1 == serviceType) { System.out.println("取消即時訂單"); } else if (2 == serviceType) { System.out.println("取消預定訂單"); } else if (3 == serviceType) { System.out.println("取消拼車訂單"); } } }
若干個月再來看就是這樣的感受
github
@Service public class CancelOrderStrategyService { @Autowired private StrategyContext context; public void process(OrderDTO orderDTO) { OrderTypeEnum orderTypeEnum = OrderTypeEnum.getByCode(orderDTO.getServiceType()); AbstractStrategy strategy = context.getStrategy(orderTypeEnum); strategy.process(orderDTO); } }
簡潔的有點過度了是否是!!!spring
下面選取了即時訂單和預定訂單的策略.ide
@Service @OrderTypeAnnotation(orderType = OrderTypeEnum.INSTANT) public class InstantOrderStrategy extends AbstractStrategy { @Override public void process(OrderDTO orderDTO) { System.out.println("取消即時訂單"); } }
@Service @OrderTypeAnnotation(orderType = OrderTypeEnum.BOOKING) public class BookingOrderStrategy extends AbstractStrategy { @Override public void process(OrderDTO orderDTO) { System.out.println("取消預定訂單"); } }
public abstract class AbstractStrategy { abstract public void process(OrderDTO orderDTO); }
每一個策略中增長了註解OrderTypeAnnotation,以標註適用於不一樣類型的策略內容.post
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited public @interface OrderTypeAnnotation { OrderTypeEnum orderType(); }
其中最爲核心的爲StrategyProcessor 策略處理器類和StrategyContext 策略上下文,this
@Component public class StrategyProcessor implements BeanFactoryPostProcessor { private static final String STRATEGY_PACKAGE = "com.lujiahao.strategy"; @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException { Map<OrderTypeEnum, Class> handlerMap = Maps.newHashMapWithExpectedSize(3); ClassScanner.scan(STRATEGY_PACKAGE, OrderTypeAnnotation.class).forEach(clazz -> { OrderTypeEnum type = clazz.getAnnotation(OrderTypeAnnotation.class).orderType(); handlerMap.put(type, clazz); }); StrategyContext context = new StrategyContext(handlerMap); configurableListableBeanFactory.registerSingleton(StrategyContext.class.getName(), context); } }
public class StrategyContext { private Map<OrderTypeEnum, Class> strategyMap; public StrategyContext(Map<OrderTypeEnum, Class> strategyMap) { this.strategyMap = strategyMap; } public AbstractStrategy getStrategy(OrderTypeEnum orderTypeEnum) { if (orderTypeEnum == null) { throw new IllegalArgumentException("not fond enum"); } if (CollectionUtils.isEmpty(strategyMap)) { throw new IllegalArgumentException("strategy map is empty,please check you strategy package path"); } Class clazz = strategyMap.get(orderTypeEnum); if (clazz == null) { throw new IllegalArgumentException("not fond strategy for type:" + orderTypeEnum.getCode()); } return (AbstractStrategy) SpringBeanUtils.getBean(clazz); } }
咱們使用了枚舉做爲Map中的key,相信你們不多有人這樣操做過,不過能夠放心操做.經過下面兩篇文章解答你們的疑問..net
策略模式極大的減小if else等模板代碼,在提高代碼可讀性的同時,也大大增長代碼的靈活性,添加新的策略便可以知足業務需求.
本人在我司業務中對策略模式的應用獲得了很好的驗證,今後不再用擔憂產品改需求.
用策略模式一時爽,一直用一直爽😏!code
完整代碼blog