设计模式-策略模式(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)由于策略模式把每个具体的策略实现都单独封装成为类,如果备选的策略很多的话,那么对象的数目就会很可观。

 

posted @ 2013-04-20 23:44  WahsonLeung  阅读(232)  评论(0编辑  收藏  举报