比方说,我们整个框架的流程是接收数据、处理数据、返回数据。但是在如何处理数据这个问题上,我们有不同的解决办法。

所以这时,我们可以将“如何处理数据”这一模块抽象出来,抽象为 strategy interface,其包含 process_data(data) -> data 方法.这样对于整个框架来说,它就不需要去考虑“处理数据”这一板块内部如何实现、采用什么算法之类的,只需要调用 .process_data() 接口就可以正常推进流程了.

Overview

classDiagram
    %% 策略接口
    class Strategy {
        <>
        +execute(data)
    }

    %% 具体策略类
    class ConcreteStrategyA {
        +execute(data)
    }
    class ConcreteStrategyB {
        +execute(data)
    }

    %% 上下文类
    class Context {
        -strategy: Strategy
        +setStrategy(strategy: Strategy)
        +doSomething()
    }

    %% 客户端类
    class Client

    %% 关系定义
    Strategy <|.. ConcreteStrategyA : 实现
    Strategy <|.. ConcreteStrategyB : 实现
    Context o-- Strategy : 聚合
    Client ..> Context : 依赖

Context 对象就是我们前面的“框架”,其内部有一个 Strategy interface 对象.ConcreteStrategyA, ConcreteStrategyB 实现了 Strategy 接口,可以对 Context 中的 Strategy 对象进行替换.Client 对象可以实例化 StrategyA,B 并调用 setStrategy() 对策略进行替换.

运行逻辑

sequenceDiagram
    participant Client
    participant Context
    participant Strategy

    Client->>ConcreteStrategy: new ConcreteStrategy()
    activate ConcreteStrategy
    Client->>Context: new Context()
    activate Context
    Client->>Context: setStrategy(strategy)
    Note right of Context: 持有策略引用
    Client->>Context: doSomething()
    Context->>Strategy: execute(data)
    activate Strategy
    Strategy-->>Context: 返回结果
    deactivate Strategy
    Context-->>Client: 返回结果
    deactivate Context
    deactivate ConcreteStrategy

与 Template Method 设计模式的区别

Strategy 设计模式的被调用者是 Context,而 Context 里的 Strategy 可以被替换.因此总的来说,Strategy 设计模式依靠组合、可替换、运行时选择

而 Template Method 的实际被调用者是 ConcreteClassX,即 Template Method 的具体实现.而 Template Method 的步骤流程其实是固定的,所以 Template Method 的本质是依靠继承、固定流程、步骤可变完成.