Skip to content

策略模式(Strategy Pattern)笔记

定义

策略模式是一种行为设计模式,它定义了一系列算法,将每个算法封装起来,并使它们可以相互替换。策略模式让算法的变化独立于使用算法的客户。

英文原文定义

The Strategy Pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.

核心概念

策略模式通过将算法封装在独立的策略类中,使得它们可以相互替换,而不影响客户端代码。这种模式基于组合而非继承,更符合"开闭原则"。

主要角色

  1. Context(上下文):维护一个对Strategy对象的引用
  2. Strategy(策略接口):定义所有支持的算法的公共接口
  3. ConcreteStrategy(具体策略):实现Strategy接口的具体算法类

优缺点

优点

  • 避免多重条件语句:替代大量的if-else或switch-case语句
  • 开闭原则:无需修改上下文即可引入新策略
  • 算法复用:可在不同环境中复用相同的策略
  • 运行时切换算法:可以在运行时动态切换对象使用的算法

缺点

  • 客户端必须了解策略差异:客户端需要知道不同策略的区别以选择合适的策略
  • 增加对象数量:每个策略都是一个类,可能增加系统中对象的数量
  • 通信开销:策略与上下文之间可能需要共享数据,增加了通信开销

解决的问题

策略模式主要解决以下经典问题:

  1. 多种算法变体:当一个系统需要在多种算法中选择一种时
  2. 算法频繁变化:当算法需要经常变化或扩展时
  3. 隐藏复杂逻辑:当需要隐藏复杂的、与算法相关的数据结构时
  4. 消除条件语句:当需要消除大量的条件语句时

实现注意事项

  1. 策略接口设计:确保策略接口足够通用,能够支持所有具体策略
  2. 上下文角色:上下文可以负责策略的创建和销毁,或者由客户端负责
  3. 共享数据:考虑策略是否需要访问上下文中的数据,以及如何传递
  4. 策略选择:明确策略选择的责任方(客户端或上下文)
  5. 性能考量:频繁创建和销毁策略对象可能影响性能,考虑对象池

与其他模式的关系

相似模式区分

  1. 状态模式

    • 策略模式:客户端主动选择策略,策略之间通常不了解彼此
    • 状态模式:状态转换通常由上下文或状态自身控制,状态之间可能相互了解
  2. 命令模式

    • 策略模式:关注算法选择
    • 命令模式:关注请求的封装和参数化
  3. 模板方法模式

    • 策略模式:使用对象组合,运行时改变行为
    • 模板方法模式:使用类继承,编译时确定算法框架

常见搭配组合

  1. 策略模式 + 工厂模式:用于创建具体的策略对象
  2. 策略模式 + 享元模式:共享策略对象以减少内存开销
  3. 策略模式 + 装饰器模式:动态添加策略行为

典型应用场景

  • 支付系统(不同支付方式)
  • 排序算法(不同排序策略)
  • 压缩算法(不同压缩策略)
  • 导航系统(不同路径计算策略)
  • 折扣计算(不同折扣策略)

代码示例(伪代码)

java
// 策略接口
interface SortingStrategy {
    void sort(int[] data);
}

// 具体策略
class BubbleSort implements SortingStrategy {
    public void sort(int[] data) { /* 冒泡排序实现 */ }
}

class QuickSort implements SortingStrategy {
    public void sort(int[] data) { /* 快速排序实现 */ }
}

// 上下文
class Sorter {
    private SortingStrategy strategy;
    
    public void setStrategy(SortingStrategy strategy) {
        this.strategy = strategy;
    }
    
    public void executeSort(int[] data) {
        strategy.sort(data);
    }
}

// 客户端代码
Sorter sorter = new Sorter();
sorter.setStrategy(new QuickSort());
sorter.executeSort(data);