介绍

在开发中也经常遇到这种情况,实现某一个功能往往有许多算法或者策略,我们在实际开发中选择不同的算法或策略来完成该功能。一般的情况是我们会把所有的算法或策略写入一个类中,通过if…else…或case语句来根据实际情况来选择具体算法或策略,但是这种方法会使这个类臃肿,维护难,当增加一种算法或策略时又要修改源代码,违反了面向对象的单一原则和开闭原则。如果将这些算法或者策略抽象出来,提供一个统一的接口,不同的算法或策略有不同的实现类,在实际使用时通过动态注入来实现算法或策略的替换,这种模式扩展性高,维护性好,也就是本次所说的策略模式。

定义

策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们相互可以替换。让算法独立于客户端变化。

使用场景

(1)需要安全的封装多种同一类型的操作时

(2)出现同一抽象类有多个子类,而又需要使用if..else..或case语句来选择具体子类时

类图

角色介绍:

  • Context - 用来操作策略的上下文环境
  • Stragety - 策略的抽象
  • ConcreteStragetyA、B - 具体的策略实现

简单实现

我们在写代码时经常会遇到对一个数组排序,排序的算法有很多比如插入排序,归并排序,冒泡排序等,我们在实际开发中要选择一种算法来对数组排序,一般情况下我们会这样写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public class Client {

private static final int INSERT_SORT = 0;//插入排序
private static final int MERGE_SORT = 1;//归并排序
private static final int BUBBLE_SORT = 2;//冒泡排序

public static void main(String[] args){
Client client = new Client();
int[] a = new int[]{1, 2, 3, 4, 5, 6};
client.show(a, INSERT_SORT);
}

//显示结果
private void show(int[] a, int type){
if(type == INSERT_SORT){
insetSort(a);
}else if (type == MERGE_SORT){
mergeSort(a);
}else if (type == BUBBLE_SORT){
bubbleSort(a);
}
for(int b : a){
System.out.print(b + " ");
}
}

//插入排序算法
private void insetSort(int[] a){
//TODO...
}

//归并排序算法
private void mergeSort(int[] a){
//TODO...
}

//冒泡排序算法
private void bubbleSort(int[] a){
//TODO...
}
}

这里并不是讨论算法,就没有给出算法的具体实现,上面我们使用type类型通过if…else…语句来动态决定使用哪一种排序算法,当我们增加一种算法时,就要在函数中增加一个判断,以此类推,这样会使代码变得臃肿,一改很多处都要改。下面用策略模式进行重构,首先定义一个抽象的排序接口。

抽象的排序接口,即抽象策略角色

1
2
3
public interface Sort{
<T> void sort(T[] a);
}

具体策略实现类

1
2
3
4
5
6
public class BubbleSort implements Sort {
@Override
public <T> void sort(T[] a) {
//这里实现冒泡排序
}
}
1
2
3
4
5
6
7
public class InsertSort implements Sort{

@Override
public <T> void sort(T[] a) {
//这里实现插入排序
}
}
1
2
3
4
5
6
7
public class MergeSort implements Sort {

@Override
public <T> void sort(T[] a) {
//这里实现归并排序
}
}

客户端,用来操作策略的上下文环境,即Context角色。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Client {

private Sort mSort;

public static void main(String[] args){
Client client = new Client();
//设置策略
Sort bubbleSort = new BubbleSort();
client.setmSort(bubbleSort);
Integer[] a = {1, 2, 3, 4, 5, 6};
client.show(a);
}

public void setmSort(Sort mSort) {
this.mSort = mSort;
}

public void show(Integer[] a){
mSort.sort(a);
for(Integer b : a){
System.out.print(b + " ");
}
}

}

通过上述实例可以清晰的看出两者的区别,前面说通过if..else语句来解决问题,而后者是通过建立抽象,将不同的算法构建成一个个具体的策略实现,通过不同的策略注入实现算法替换。

结语

策略模式主要用来分离算法,在简化逻辑结构的同时,增强了系统的可读性,稳定性,可扩展性,这对于复杂的业务逻辑显得更为直观,通过建立抽象,注入不同实现,从而达到很好的扩展性。

本文源码相关位置