Strategy Design Pattern - tenji/ks GitHub Wiki

策略模式

策略模式(Strategy/Policy Pattern)是一种行为软件设计模式,可以在运行时选择算法,可让你定义一系列算法,将每个算法放入单独的类中,并使它们的对象可互换。

策略模式就是匿名函数(Lambda 函数)吗?

Java 8 引入了 lambda 函数的支持,它可以作为策略模式的更简单的替代方案。但是策略模式并不完全等同于匿名函数(Lambda 函数)。

匿名函数(Lambda 函数)能完全替代策略模式吗?

不能。因为 Lambda 表达式只能声明一个方法,但是一个策略接口可以有多个方法,比如当下面示例中的 SortingStrategy 类是以下定义时,Lambda 函数就没法替代策略模式:

public interface SortingStrategy {
    void beforeSort(int[] array);

    void sort(int[] array);
}

一、结构

strategy-structure

二、代码样例

SortingContext 类(Context)

public class SortingContext {
    private SortingStrategy sortingStrategy;

    public SortingContext(SortingStrategy sortingStrategy) {
        this.sortingStrategy = sortingStrategy;
    }

    public void setSortingStrategy(SortingStrategy sortingStrategy) {
        this.sortingStrategy = sortingStrategy;
    }

    public void performSort(int[] array) {
        sortingStrategy.sort(array);
    }
}

SortingStrategy 类(Strategy Interface)

public interface SortingStrategy {
    void sort(int[] array);
}

BubbleSortStrategy 类(Concrete Strategy1)

// BubbleSortStrategy
public class BubbleSortStrategy implements SortingStrategy {
    @Override
    public void sort(int[] array) {
        // Implement Bubble Sort algorithm
        System.out.println("Sorting using Bubble Sort");
    }
}

MergeSortStrategy 类(Concrete Strategy2)

// MergeSortStrategy
public class MergeSortStrategy implements SortingStrategy {
    @Override
    public void sort(int[] array) {
        // Implement Merge Sort algorithm
        System.out.println("Sorting using Merge Sort");
    }
}

QuickSortStrategy 类(Concrete Strategy3)

// QuickSortStrategy
public class QuickSortStrategy implements SortingStrategy {
    @Override
    public void sort(int[] array) {
        // Implement Quick Sort algorithm
        System.out.println("Sorting using Quick Sort");
    }
}

Driver Program

public class Client {
    public static void main(String[] args) {
        // Create SortingContext with BubbleSortStrategy
        SortingContext sortingContext = new SortingContext(new BubbleSortStrategy());
        int[] array1 = {5, 2, 9, 1, 5};
        sortingContext.performSort(array1); // Output: Sorting using Bubble Sort

        // Change strategy to MergeSortStrategy
        sortingContext.setSortingStrategy(new MergeSortStrategy());
        int[] array2 = {8, 3, 7, 4, 2};
        sortingContext.performSort(array2); // Output: Sorting using Merge Sort

        // Change strategy to QuickSortStrategy
        sortingContext.setSortingStrategy(new QuickSortStrategy());
        int[] array3 = {6, 1, 3, 9, 5};
        sortingContext.performSort(array3); // Output: Sorting using Quick Sort
    }
}

三、Strategy Pattern in Java

策略模式在 Java 代码中非常常见。它经常用于各种框架中,为用户提供一种无需扩展类即可更改类行为的方法。

四、优点

  • 你可以在运行时交换对象内部使用的算法;
  • 你可以将算法的实现细节与使用该算法的代码隔离开来;
  • 你可以用组合代替继承
  • 符合开闭原则。你可以引入新策略,而无需更改上下文。

五、缺点

  • 策略模式附带的新类和接口可能会使程序变得过于复杂,特别是只有几种算法并且它们很少改变的情况下,没有真正的理由去使用策略模式;
  • 客户端必须了解策略之间的差异,才能选择合适的策略,因为这个策略是需要客户端指定的;
  • 策略模式额外的类和接口会使代码变得臃肿,使用匿名函数替代会是一个更好的选择,许多现代编程语言都具有函数类型支持。

六、策略模式 vs 状态模式

状态模式可以被视为策略模式的延伸,因为状态模式是根据状态做不同的事情,也可以理解为策略模式的根据不同策略跑不同的算法,建议关注两种策略在静态结构(类图)和动态结构(时序图)上的区别。

相同点:

  • 两种模式均基于组合:它们通过将一些工作委托给辅助对象来改变上下文的行为。

不同点:

  • 状态对象存储包含它们的上下文对象的引用。策略对象则不然;
  • 状态对象可以替换自身(即:将上下文对象的状态更改为其他状态),而策略对象则不允许;
  • 策略对象作为参数传递给上下文对象,而状态对象由上下文对象本身创建;
  • 策略对象仅处理单个特定任务,而状态对象为上下文对象所做的所有事情(或几乎所有事情)提供底层实现。

策略模式时序图:

状态模式时序图:

更多关于状态模式,传送门

七、策略模式 vs 模板模式

关于两者的比较,传送门

∞、参考链接