策略设计模式
1. 简单介绍
策略模式(Strategy)是一种行为型设计模式。该模式定义了一个算法簇,用不同的类分别封装起来,让他们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。很好的满足了开闭原则。
2. 使用场景
- 多个类只区别在表现行为不同,可以使用Strategy模式,在运行时动态选择具体要执行的行为
- 需要在不同情况下使用不同的策略(算法),或者策略还可能在未来用其它方式来实现
- 对客户隐藏具体策略(算法)的实现细节,彼此完全独立
3. 场景举例
我们在对一个数组进行排序时,通常会使用Arrays.sort(T[ ] a, Comparator<? super T> c)方法。该方法通过传入一个Comparator,指定数组的排序算法。这是策略模式的一个典型的使用场景。抽离出需要动态变化的排序算法部分(数组的排序算法),根据用户的需要,传入不同的Comparator对数组采用不同的算法进行排序。当用户需要采用新的排序算法时,只需要新增一个排序算法,传入sort方法中即可,很好的满足了开闭原则。
4. UML类图
5. 具体实现
描述
- 背景:对数组进行排序,通过策略模式来实现不同场景下的切换不同排序算法进行排序
- Strategy:策略类,定义了排序算法的接口
- BubbleSortStrategy:具体的策略类,冒泡排序
- InsertSortStrategy:具体的策略类,插入排序
- Context:上下文,维护着Strategy
- Client:客户端
代码实现
Strategy.java
/**
* 策略类,定义了排序算法的接口
*/
public interface Strategy<T extends Comparable> {
void sort(T[] t);
default void swap(T[] t, int leftIdx, int rightIdx) {
T tempT = t[leftIdx];
t[leftIdx] = t[rightIdx];
t[rightIdx] = tempT;
}
}
BubbleSortStrategy.java
/**
* 冒泡排序
*/
public class BubbleSortStrategy<T extends Comparable> implements Strategy<T> {
@Override
public void sort(T[] t) {
for (int i = 0; i < t.length; i++) {
for (int j = 0; j < t.length - i - 1; j++) {
if (t[i].compareTo(t[j]) > 0) {
swap(t, i, j);
}
}
}
}
}
InsertSortStrategy.java
/**
* 插入排序
*/
public class InsertSortStrategy<T extends Comparable> implements Strategy<T> {
@Override
public void sort(T[] t) {
for (int i = 1; i < t.length; i++) {
for (int j = i; j > 0; j--) {
if (t[j].compareTo(t[j - 1]) > 0) {
swap(t, j, j - 1);
}
}
}
}
}
Context.java
/**
* 上下文
*/
public class Context {
/**
* 具体的排序策略由用户传入,利用了多态的特性
*/
public static <T extends Comparable> void sortWithStrategy(T[] t, Strategy strategy) {
strategy.sort(t);
}
}
Client.java
/**
* 客户端
*/
public class Client {
public static void main(String[] args) {
// 创建待排序数组
Integer[] beSortedArr = new Integer[]{1, 5, 9, 7, 5, 3, 6, 5, 4, 8, 5, 2};
// 场景一:使用冒泡排序对数据进行排序
Context.sortWithStrategy(beSortedArr, new BubbleSortStrategy<Integer>());
for (Integer integer1 : beSortedArr) {
System.out.println(integer1);
}
// 场景二:使用插入排序对数组进行排序
// 利用多态的特性,改变排序的策略(算法)
Context.sortWithStrategy(beSortedArr, new InsertSortStrategy<Integer>());
}
}
7. 源码展示
JDK
中的Arrays.sort(T[ ] a, Comparator<? super T> c)方法的实现采用策略设计模式。该方法的作用是对数组a进行排序,而具体排序的策略则是通过用户传入的Comparator决定的。其中源码如下:
Comparator.java
/**
* 对应策略模式中Strategy接口,定义了排序算法compare方法
*/
public interface Comparator<T> {
int compare(T o1, T o2);
}
TimSort.java
/**
* 对应Context角色,持有Comparator(即策略类)的引用
*/
class TimSort<T> {
/**
* 聚合Comparator接口,通过私有构造方法传入
*/
private final Comparator<? super T> c;
/**
* 私有构造方法,内部调用传入Comparator
*/
private TimSort(T[] a, Comparator<? super T> c, T[] work, int workBase, int workLen) {
this.a = a;
// 为Comparator赋值
this.c = c;
// 其余代码略
}
/**
* 用户可以根据要求,传入具体的策略类作为数据排序的比较器
* 程序在运行时会使用用户传入的比较器作为数组排序算法
*/
public static <T> void sort(T[] a, Comparator<? super T> c) {
if (c == null) {
sort(a);
} else {
if (LegacyMergeSort.userRequested)
legacyMergeSort(a, c);
else
TimSort.sort(a, 0, a.length, c, null, 0, 0);
}
}
}
注: 具体的策略类(ConcreteStratagy),由用户自己进行实现。在使用Arrays.sort()方法时,传入即可。