跳至正文
来两杯美式
返回

设计模式之策略模式:算法家族,自由切换

By 来两杯美式
发布于

这是 2020 年 6 月整理的设计模式专题第十篇。策略模式是行为型模式的入门首选——把”算法”抽出来独立变化,消除满天飞的 if/else。电商促销、排序比较器都是它的经典应用。

简单说明

策略模式(Strategy Pattern):定义算法家族,分别封装起来,让他们之间可以相互替换

传统 if/else:          策略模式:
if (type == 返现) {...}        策略接口 <── 返现策略
else if (type == 立减) {...}        ├── 立减策略
else if (type == 满减) {...}        └── 满减策略
(算法和业务耦合在一起)      (算法独立封装,可替换)

代码实现

/**
 * 促销策略抽象类
 */
public interface PromotionStrategy {
    void doPromotion();
}

/**
 * 返现策略
 */
public class FanXianPromotionStrategy implements PromotionStrategy {
    @Override
    public void doPromotion() {
        System.out.println("返现促销,返回的金额存放到慕课网用户的余额中");
    }
}

/**
 * 立减策略
 */
public class LiJianPromotionStrategy implements PromotionStrategy {
    @Override
    public void doPromotion() {
        System.out.println("立减促销,课程的价格直接减去配置的价格");
    }
}

/**
 * 空策略:没有任何促销时兜底,避免空指针
 */
public class EmptyPromotionStrategy implements PromotionStrategy {
    @Override
    public void doPromotion() {
        System.out.println("无促销");
    }
}

/**
 * 促销策略工厂:根据促销类型的 key 返回特定促销策略
 */
public class PromotionStrategyFactory {
    private static Map<String, PromotionStrategy> PROMOTION_STRATEGY_MAP = new HashMap<>();

    static {
        PROMOTION_STRATEGY_MAP.put(PromotionKey.LIJIAN, new LiJianPromotionStrategy());
        PROMOTION_STRATEGY_MAP.put(PromotionKey.FANXIAN, new FanXianPromotionStrategy());
    }

    private static final PromotionStrategy NON_PROMOTION = new EmptyPromotionStrategy();

    private PromotionStrategyFactory() {
    }

    public static PromotionStrategy getPromotionStrategy(String promotionKey) {
        PromotionStrategy promotionStrategy = PROMOTION_STRATEGY_MAP.get(promotionKey);
        return promotionStrategy == null ? NON_PROMOTION : promotionStrategy;
    }
}

角色:策略接口(PromotionStrategy)+ 具体策略(返现/立减/空策略)+ 策略工厂(按 key 取策略)。

消除 if/else:传统的 if (type == 返现) ... else if (type == 立减) 被”查 Map 取策略”取代;新增策略时只加一个类 + 一行注册,不改业务代码。

策略模式的价值

对比项传统 if/else策略模式
算法与业务耦合在一起算法独立封装
新增算法改业务代码加一个策略类
开闭原则不满足满足
可测试性混杂难测每个策略独立测试

注意:策略模式解决的是”同一种业务有多种算法”的切换问题。如果只是简单的一两个分支,直接 if/else 更简单,不要为了模式而模式。

现实中的应用

场景说明
ComparatorCollections.sort(list, comparator) 传入不同比较策略
Spring Resource不同资源类型(classpath/file/url)对应不同 Resource 实现
支付方式支付宝/微信/银联,同一支付接口不同实现
线程池拒绝策略AbortPolicy / CallerRunsPolicy / DiscardPolicy

小结


分享这篇文章:
通过邮件分享这篇文章✓ 链接已复制
查看系列全部文章
  1. 01.软件设计原则:SOLID + KISS / YAGNI / LOD 全景
  2. 02.设计模式之原型模式,及深浅拷贝
  3. 03.设计模式之工厂模式:简单工厂、工厂方法与抽象工厂
  4. 04.设计模式之建造者模式:复杂对象的组装艺术
  5. 05.设计模式之适配器模式:让不兼容的接口协同工作
  6. 06.设计模式之桥接模式:抽象与实现分离,各自独立变化
  7. 07.设计模式之装饰者模式:动态增强,比继承更有弹性
  8. 08.设计模式之代理模式:静态代理与 JDK 动态代理
  9. 09.设计模式之外观模式:统一门面,简化子系统调用
  10. 10.设计模式之享元模式:共享细粒度对象,降低内存占用
  11. 11.设计模式之策略模式:算法家族,自由切换
  12. 12.设计模式之模板方法模式:固定骨架,可变步骤
  13. 13.设计模式之观察者模式:一对多依赖,状态变更自动通知
  14. 14.设计模式之责任链模式:请求逐级传递,动态组合处理者
  15. 15.设计模式之状态模式:状态变,行为变
  16. 16.设计模式之迭代器模式:不暴露内部实现,顺序访问集合

上一篇
设计模式之模板方法模式:固定骨架,可变步骤
下一篇
DDD 复杂业务系统设计(总结):从领域到微服务,一张图看懂 DDD 落地全流程