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);
}
一、结构
二、代码样例
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 模板模式
关于两者的比较,传送门