设计模式-策略模式(Strategy)
策略模式属于对象的行为模式。其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。
策略模式的结构
策略模式是对算法的包装,是把使用算法的责任和算法本身分割开来,委派给不同的对象管理。策略模式通常把一个系列的算法包装到一系列的策略类里面,作为一个抽象策略类的子类。用一句话来说,就是:“准备一组算法,并将每一个算法封装起来,使得它们可以互换”。下面就以一个示意性的实现讲解策略模式实例的结构。
模式中的角色
1 抽象策略类(Strategy):定义所有支持的算法的公共接口。
2 具体策略类(Concrete Strategy):封装了具体的算法或行为,继承于Strategy类。
3 上下文类(Context):用一个ConcreteStrategy来配置,维护一个对Strategy对象的引用。
代码:
抽象策略类
1 public interface Strategy {
2 /**
3 * 策略方法
4 */
5 public void strategyInterface();
6 }
具体策略类
1 public class ConcreteStrategyA implements Strategy {
2
3 @Override
4 public void strategyInterface() {
5 //相关的业务
6 }
8 }
1 public class ConcreteStrategyB implements Strategy {
2
3 @Override
4 public void strategyInterface() {
5 //相关的业务
6 }
7 }
1 public class ConcreteStrategyC implements Strategy {
2
3 @Override
4 public void strategyInterface() {
5 //相关的业务
6 }
7 }
环境角色类
1 public class Context {
2 //持有一个具体策略的对象
3 private Strategy strategy;
4 /**
5 * 构造函数,传入一个具体策略对象
6 * @param strategy 具体策略对象
7 */
8 public Context(Strategy strategy){
9 this.strategy = strategy;
10 }
11 /**
12 * 策略方法
13 */
14 public void contextInterface(){
15
16 strategy.strategyInterface();
17 }
18 }
适用场景
1 当实现某个功能需要有不同算法要求时
2 不同时间应用不同的业务规则时
实例
排序是我们经常接触到的算法,实现对一个数组的排序有很多方法,即可以采用不同的策略。下面给出了排序功能的策略模式的解决方案。
排序算法策略
1 /**
2 * @author Wahson Leung
3 * @version 2013-4-20
4 *
5 */
6 public interface SortStrategy {
7 public int[] sort(int[] arr);
8 }
直接插入排序
1 /**
2 * @author Wahson Leung
3 * @version 2013-4-20
4 *
5 */
6 public class InsertSort implements SortStrategy {
7
8 /*
9 * 直接插入排序
10 *
11 * @param arr
12 *
13 * @return a sorted array
14 */
15 @Override
16 public int[] sort(int[] arr) {
17
18 for (int i = 1; i < arr.length; i++) {
19 int tmp = arr[i];
20 int j = i;
21 while (j > 0 && tmp < arr[j - 1]) {
22 arr[j] = arr[j - 1];
23 j--;
24 }
25 arr[j] = tmp;
26
27 for (int e : arr) {
28 System.out.print(e + " ");
29 }
30 System.out.println();
31 }
32 return arr;
33 }
34 }
冒泡排序
1 /**
2 * @author Wahson Leung
3 * @version 2013-4-20
4 *
5 */
6 public class BubbleSort implements SortStrategy {
7
8 /*
9 * 冒泡排序(升序)
10 *
11 * @param arr to be sorted
12 *
13 * @return a sorted array
14 */
15 @Override
16 public int[] sort(int[] arr) {
17 boolean flag = false;
18 int length = arr.length;
19 while (true) {
20 flag = true;
21 for (int i = 0; i < length - 1; i++) {
22 if (arr[i] > arr[i + 1]) {
23 int tmp = arr[i];
24 arr[i] = arr[i + 1];
25 arr[i + 1] = tmp;
26 flag = false;
27 }
28 }
29 length--;
30 if (flag) {
31 break;
32 }
33 }
34 return arr;
35 }
36 }
排序上下文
1 /**
2 * @author Wahson Leung
3 * @version 2013-4-20
4 *
5 */
6 public class SortContext {
7 private SortStrategy strategy;
8
9 public SortContext(SortStrategy strategy) {
10 this.strategy = strategy;
11 }
12
13 public int[] sort(int arr[]) {
14 return strategy.sort(arr);
15 }
16 }
客户端代码
1 /**
2 * @author Wahson Leung
3 * @version 2013-4-20
4 *
5 */
6 public class Test {
7 public static void main(String args[]) {
8 int arr[] = { 4, 3, 2, 5, 7, 8, 10, 1, 6, 9, 0, -1, 22, 33, 54, 2, 56,
9 75, 3, 2, 5, 7, 8, 9, 0, 23 };
10 // 使用冒泡排序
11 SortStrategy bubble = new BubbleSort();
12 SortContext context1 = new SortContext(bubble);
13 int sortedArr1[] = context1.sort(arr);
14
15 // 使用直接插入排序
16 SortStrategy insert = new InsertSort();
17 SortContext context2 = new SortContext(insert);
18 int sortedArr2[] = context2.sort(arr);
19 }
20 }
从上面的示例可以看出,策略模式仅仅封装算法,提供新的算法插入到已有系统中,以及老算法从系统中“退休”的方法,策略模式并不决定在何时使用何种算法。在什么情况下使用什么算法是由客户端决定的。
认识策略模式
策略模式的重心
策略模式的重心不是如何实现算法,而是如何组织、调用这些算法,从而让程序结构更灵活,具有更好的维护性和扩展性。
算法的平等性
策略模式一个很大的特点就是各个策略算法的平等性。对于一系列具体的策略算法,大家的地位是完全一样的,正因为这个平等性,才能实现算法之间可以相互替换。所有的策略算法在实现上也是相互独立的,相互之间是没有依赖的。
所以可以这样描述这一系列策略算法:策略算法是相同行为的不同实现。
运行时策略的唯一性
运行期间,策略模式在每一个时刻只能使用一个具体的策略实现对象,虽然可以动态地在不同的策略实现中切换,但是同时只能使用一个。
公有的行为
经常见到的是,所有的具体策略类都有一些公有的行为。这时候,就应当把这些公有的行为放到共同的抽象策略角色Strategy类里面。当然这时候抽象策略角色必须要用Java抽象类实现,而不能使用接口。
这其实也是典型的将代码向继承等级结构的上方集中的标准做法。
策略模式的优点
1、 策略模式是一种定义一系列算法的方法,从概念上来看,所有算法完成的都是相同的工作,只是实现不同,它可以以相同的方式调用所有的算法,减少了各种算法类与使用算法类之间的耦合。
2 、策略模式的Strategy类为Context定义了一系列的可供重用的算法或行为。继承有助于析取出这些算法的公共功能。
3 、策略模式每个算法都有自己的类,可以通过自己的接口单独测试。因而简化了单元测试。
4、策略模式将具体算法或行为封装到Strategy类中,可以在使用这些类中消除条件分支(避免了不同行为堆砌到一个类中)。
策略模式的缺点
(1)客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道算法或行为的情况。
(2)由于策略模式把每个具体的策略实现都单独封装成为类,如果备选的策略很多的话,那么对象的数目就会很可观。