介绍
策略模式首先是一种行为型模式,把定义的一系列的算法,封装起来,然后根据用户的需求来决定采用哪个算法,并且算法的修改对用户也没影响。

策略模式UML图.png
Context:策略上下文。
Strategy:抽象策略
ConcreteStrategy:具体策略
举例
我们定义了一个整型数组,数组里面的整数都是没有顺序的,然后用户的需求是打算,从小到大排列。然后根据用户的需求来决定采用哪种算法来排序。每个算法之间也可以相互替换,并且这种替换对于用户来说是没有影响的。
策略模式代码
- 抽象策略接口:排序接口
public interface ISort {
public int[] sort(int[] strArray);
}
- 具体策略1:直接插入排序
/**
* @description 直接插入排序
*
* @author sunpy
* @date 2018年10月21日 下午8:08:15
*/
public class DirectInsertSort implements ISort{
@Override
public int[] sort(int[] strArray) {
for (int i = 1 ; i < strArray.length ; i++) {
int nowValue = strArray[i];
int j = i - 1;
while (j >= 0 && nowValue < strArray[j]) {
strArray[j + 1] = strArray[j];
j--;
}
strArray[j + 1] = nowValue;
}
return strArray;
}
}
- 具体策略2:冒泡排序
/**
* @description 冒泡排序
*
* @author sunpy
* @date 2018年10月21日 下午8:08:05
*/
public class BubbleSort implements ISort{
@Override
public int[] sort(int[] strArray) {
for (int i = 0 ; i < strArray.length ; i++) {
for (int j = i + 1 ; j < strArray.length ; j++) {
if (strArray[i] > strArray[j]) {
int temp = strArray[i];
strArray[i] = strArray[j];
strArray[j] = temp;
}
}
}
return strArray;
}
}
- 引用策略类
/**
* @description 引用策略类
*
* @author sunpy
* @date 2018年10月21日 下午8:07:40
*/
public class SortQuote {
private ISort iSort;
public SortQuote(ISort iSort) {
this.iSort = iSort;
}
public int[] useSort(int[] strArray) {
return iSort.sort(strArray);
}
}
测试:
public class MyTest {
public static void printArr(int[] arr) {
for (int i : arr) {
System.out.print(i);
}
}
public static void main(String[] args) throws Exception {
int[] arr = {2,6,7,1,3,8,4,5};
SortQuote sq1 = new SortQuote(new DirectInsertSort());
SortQuote sq2 = new SortQuote(new BubbleSort());
int[] arr1 = sq1.useSort(arr);
printArr(arr1);
System.out.printf("\n");
int[] arr2 = sq2.useSort(arr);
printArr(arr2);
}
}

结果
策略模式优化if / else
我们在写代码中:
if ("BubbleSort".equals(type)) {
....
} else if ("DirectInsertSort".equals(type)) {
....
} else {
....
}
不同策略:
public interface ISort {
public Integer[] sort(Integer[] strArray);
}
@Service("bubbleSort")
public class BubbleSortImpl implements ISort{
@Override
public Integer[] sort(Integer[] strArray) {
for (int i = 0 ; i < strArray.length ; i++) {
for (int j = i + 1 ; j < strArray.length ; j++) {
if (strArray[i] > strArray[j]) {
int temp = strArray[i];
strArray[i] = strArray[j];
strArray[j] = temp;
}
}
}
return strArray;
}
}
@Service("directInsertSort")
public class DirectInsertSortImpl implements ISort{
@Override
public Integer[] sort(Integer[] strArray) {
for (int i = 1 ; i < strArray.length ; i++) {
int nowValue = strArray[i];
int j = i - 1;
while (j >= 0 && nowValue < strArray[j]) {
strArray[j + 1] = strArray[j];
j--;
}
strArray[j + 1] = nowValue;
}
return strArray;
}
}
优化第一步:使用策略模式 + 简单工厂模式实现将不同条件的业务委派给不同的类去实现
抽象策略、具体策略与之前一样,不发生变化,现在修改策略上下文,然后根据输入不同的类型去调用不同类的不同方法。
@Service
public class SortStrategy {
@Autowired
private ISort bubbleSort;
@Autowired
private ISort directInsertSort;
public Integer[] doSort(Integer[] strArray, String type) {
if (Objects.equals(type, "BubbleSort")) {
return bubbleSort.sort(strArray);
} else if (Objects.equals(type, "DirectInsertSort")) {
return directInsertSort.sort(strArray);
}
return null;
}
}
理解:引入工厂模式,本身就是将代码耦合在了一起,违背了开闭原则。实际上if / else根本没有消除只是转移到上下文,还是存在ifelse问题。
优化第二步:使用策略模式+享元模式,将不同的策略存储起来,使用List来存储获取,将List交由spring管理。
@Service
public class SortStrategy {
@Autowired
private List<ISort> storeSortList;
public Integer[] doSort(Integer[] strArray, String type) {
ISort selectedSort = storeSortList.stream().filter(iSort -> iSort.currentSortStrategy(type)).findFirst().orElse(null);
if (Objects.isNull(selectedSort)) {
throw new CommonException("当前不存在映射的策略");
}
return selectedSort.sort(strArray);
}
}
public interface ISort {
public Integer[] sort(Integer[] strArray);
// 查找当前使用哪种策略
public boolean currentSortStrategy(String sortName);
}
@Service("bubbleSort")
public class BubbleSortImpl implements ISort{
@Override
public Integer[] sort(Integer[] strArray) {
for (int i = 0 ; i < strArray.length ; i++) {
for (int j = i + 1 ; j < strArray.length ; j++) {
if (strArray[i] > strArray[j]) {
int temp = strArray[i];
strArray[i] = strArray[j];
strArray[j] = temp;
}
}
}
return strArray;
}
@Override
public boolean currentSortStrategy(String sortName) {
return Objects.equals(SortedStrategyEnum.BUBBLE_SORT.getName(), sortName);
}
}
优化第三步:既然我们根据名称去找集合List中对应的策略类,那么我们可以通过Map集合来建立这种映射结构。
@Service
public class SortStrategy {
@Autowired
private Map<String, ISort> storeSortMap;
public Integer[] doSort(Integer[] strArray, String type) {
ISort selectedSort = storeSortMap.get(type);
if (Objects.isNull(selectedSort)) {
throw new CommonException("当前不存在映射的策略");
}
return selectedSort.sort(strArray);
}
}
理解:既然维护映射关系,我们可以使用SPI方式维护,通过SPI技术来动态发现java服务。
优化第四步:使用SPI来代替Map,映射存储类名与接口,实现动态发现服务,调用不同策略。

配置

配置文件内容
策略上下文实现:
public class SortStrategy {
public void doSort(Integer[] strArray, Class<?> clazz) {
ServiceLoader<ISort> serviceLoader = ServiceLoader.load(ISort.class);
serviceLoader.forEach(iSort -> {
if (clazz.getCanonicalName().equals(iSort.getClass().getCanonicalName())) {
iSort.sort(strArray);
}
});
}
}
理解:上面的代码只是将原本的对象和类名的映射关系从Map转移到了文件而已。
SPI技术可参考:https://www.jianshu.com/p/06f8082dadd3