還在用if else?策略模式瞭解一下!

在公司負責的就是訂單取消業務,老系統中各類類型訂單取消都是經過if else 判斷不一樣的訂單類型進行不一樣的邏輯。在經歷老系統的折磨和產品需求的不斷變動,決定進行一次大的重構:消滅 if else。java

接下來就向你們介紹下是如何消滅 if else。git

1. if else模式

@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

2. 策略模式

2.1 策略模式實現的Service

@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

2.2 各類類型策略實現及抽象策略類

下面選取了即時訂單和預定訂單的策略.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);
}

2.3 策略類型註解

每一個策略中增長了註解OrderTypeAnnotation,以標註適用於不一樣類型的策略內容.post

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface OrderTypeAnnotation {
    OrderTypeEnum orderType();
}

2.4 策略處理器類StrategyProcessor和策略上下文StrategyContext

其中最爲核心的爲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);
    }
}
  • 首先會掃描指定包中標有@OrderTypeAnnotation的類
  • 將符合類的對應的枚舉值做爲key,對應的類做爲value,保存在策略Map中
  • 初始化StrategyContext,並註冊到spring容器中,同時將策略Map傳入其中

咱們使用了枚舉做爲Map中的key,相信你們不多有人這樣操做過,不過能夠放心操做.經過下面兩篇文章解答你們的疑問..net

3. 總結

策略模式極大的減小if else等模板代碼,在提高代碼可讀性的同時,也大大增長代碼的靈活性,添加新的策略便可以知足業務需求.
本人在我司業務中對策略模式的應用獲得了很好的驗證,今後不再用擔憂產品改需求.
用策略模式一時爽,一直用一直爽😏!code

4. 代碼

完整代碼blog

Tips

  • 歡迎收藏和轉發,感謝你的支持!(๑•̀ㅂ•́)و✧
  • 歡迎關注個人公衆號:莊裏程序猿,讀書筆記教程資源第一時間得到!

相關文章
相關標籤/搜索