设计模式(10)——策略模式

策略模式

一. 概述

  它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化不会影响到使用算法的客户端。

二. 模式解读

2.1 策略模式的一般化类图

2.2 模式中的角色

2.1 策略类(Stratege):定义所有支持的算法的公共接口。

2.2 具体策略类(Concrete Stratege):封装了具体的算法或行为,继承于Stratege类。

2.3 上下文类(Context):用一个ConcreteStratege来配置,维护一个对Stratege对象的引用。

2.3、代码结构

Strategy

[java]  view plain copy print ?
  1. // 策略类,定义了所有支持的算法的公共接口  
  2. public interface Strategy {  
  3.     // 策略类中支持的算法,当然还可以有更多,这里只定义了一个。  
  4.     public  void algorithm();  
  5. }  

具体策略类A

[java]  view plain copy print ?
  1. public class ConcreteStrategeA implements Strategy {  
  2.   
  3.     @Override  
  4.     public void algorithm() {  
  5.         System.out.println("算法A中的实现");  
  6.   
  7.     }  
  8.   
  9. }  

具体策略类B

[java]  view plain copy print ?
  1. public class ConcreteStrategeB implements Strategy {  
  2.   
  3.     @Override  
  4.     public void algorithm() {  
  5.         System.out.println("算法B中的实现");  
  6.   
  7.     }  
  8.   
  9. }  

上下文类

[java]  view plain copy print ?
  1. // 承上启下的算法调用  
  2.   
  3. class Context {  
  4.     private Strategy strategy;  
  5.   
  6.     // 传入具体策略对象  
  7.   
  8.     public Context(Strategy strategy) {  
  9.         this.strategy = strategy;  
  10.     }  
  11.   
  12.     // 根据策略对象的值判断调用的算法类  
  13.   
  14.     public void ContextInterface() {  
  15.         strategy.algorithm();  
  16.     }  
  17. }  

三. 模式总结

3.1 优点

  1. 策略模式是一种定义一系列算法的方法,从概念上来看,所有算法完成的都是相同的工作,只是实现不同,它可以以相同的方式调用所有的算法,减少了各种算法类与使用算法类之间的耦合。
  2. 策略模式的Stratege类为Context定义了一系列的可供重用的算法或行为。继承有助于析取出这些算法的公共功能。
  3. 策略模式每个算法都有自己的类,可以通过自己的接口单独测试。因而简化了单元测试。
  4. 策略模式将具体算法或行为封装到Stratege类中,可以在使用这些类中消除条件分支(避免了不同行为堆砌到一个类中)。

3.2 缺点

    将选择具体策略的职责交给了客户端,并转给Context对象

3.3 适用场景

  • 当实现某个功能需要有不同算法要求时
  • 不同时间应用不同的业务规则时

3.4设计原则

    设计原则是把一个类中经常改变或者将来可能改变的部分提取出来,作为一个接口(c++z中可以用虚类),然后在类中包含这个对象的实例,这样类的实例在运行时就可以随意调用实现了这个接口的类的行为。下面是一个例子。  
    策略模式属于对象行为型模式,主要针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响 到客户端的情况下发生变化。通常,策略模式适用于当一个应用程序需要实现一种特定的服务或者功能,而且该程序有多种实现方式时使用。

四. 应用实例1:(排序)

排序是我们经常接触到的算法,实现对一个数组的排序有很多方法,即可以采用不同的策略。下面给出了排序功能的策略模式的解决方案。

实现类图

代码

排序策略接口

[html]  view plain copy print ?
  1. public interface SortStratege {  
  2.     // 排序  
  3.     public int[] Sort(int[] array);  
  4. }  

冒泡排序策略

[java]  view plain copy print ?
  1. // 冒泡排序  
  2.   
  3. public class BubbleSort implements SortStratege {  
  4.   
  5.     public int[] Sort(int[] array) {  
  6.         // 实现冒泡排序算法  
  7.         for (int i = 0; i < array.length; i++) {  
  8.             for (int j = i + 1; j < array.length; j++) {  
  9.                 if (array[i] > array[j]) {  
  10.                     int temp = array[j];  
  11.                     array[j] = array[i];  
  12.                     array[i] = temp;  
  13.                 }  
  14.             }  
  15.         }  
  16.   
  17.         return array;  
  18.     }  
  19. }  

插入排序策略

[java]  view plain copy print ?
  1. //插入排序  
  2. public class InsertSort implements SortStratege {  
  3.   
  4.     // 插入排序算法(递增排序)  
  5.     public int[] Sort(int[] array) {  
  6.         // 实现插入排序算法  
  7.         int temp;  
  8.         int i, j, n;  
  9.         n = array.length;  
  10.   
  11.         for (i = 1; i < n; i++) {  
  12.             temp = array[i];  
  13.             for (j = i; j > 0; j--) {  
  14.                 if (temp < array[j - 1])  
  15.                     array[j] = array[j - 1];  
  16.                 else  
  17.                     break;  
  18.   
  19.                 array[j] = temp;  
  20.             }  
  21.         }  
  22.         return null;  
  23.     }  
  24. }  

排序上下文

[java]  view plain copy print ?
  1. public class SortContext {  
  2.     private int[] m_Array;  
  3.     private SortStratege m_Stratege;  
  4.   
  5.     // 初始化时将要排序的数组和排序策略传入给Context  
  6.   
  7.     public SortContext(int[] array, SortStratege stratege) {  
  8.         m_Array = array;  
  9.         m_Stratege = stratege;  
  10.     }  
  11.   
  12.     // 调用排序算法  
  13.   
  14.     public int[] Sort() {  
  15.         int[] result = m_Stratege.Sort(this.m_Array);  
  16.   
  17.         return result;  
  18.     }  
  19. }  

Client

[java]  view plain copy print ?
  1. public class Client {  
  2.     public static void main(String[] args) {  
  3.         int[] array = new int[] { 12891822 };  
  4.   
  5.         //使用冒泡排序算法进行排序  
  6.         SortStratege sortStratege = new BubbleSort();  
  7.         SortContext sorter = new SortContext(array, sortStratege);  
  8.         int[] result = sorter.Sort();  
  9.           
  10.         for (int i : result) {  
  11.             System.out.println(i);  
  12.         }  
  13.   
  14.         //使用插入排序算法进行排序  
  15.         SortStratege sortStratege2 = new InsertSort();  
  16.         SortContext sorter2 = new SortContext(array, sortStratege2);  
  17.         int[] result2 = sorter.Sort();  
  18.           
  19.         for (int i : result2) {  
  20.             System.out.println(i);  
  21.         }  
  22.   
  23.     }  
  24. }  

五. 应用实例2:(诸葛亮三个锦囊)

刘备要到江东娶老婆了,走之前诸葛亮给赵云(伴郎)三个锦囊妙计,说是能解决棘手问题,嘿,还别说,真解决了大问题,搞到最后是周瑜陪了夫人又折兵,那咱们先看看这个场景是什么样子的。

先说说这个场景中的要素:三个妙计,一个锦囊,一个赵云,妙计是诸葛亮给的,妙计放在锦囊里,俗称就是锦囊妙计嘛,那赵云就是一个干活的人,从锦囊取出妙计,执行,然后获胜。

三个妙计是同一类型的东西,那咱就写个接口:

[java]  view plain copy print ?
  1. /** 
  2.  * 首先定义一个策略接口,这是诸葛亮给赵云的三个锦囊妙计的接口。 
  3.  */  
  4. public interface IStrategy {  
  5.     //每个锦囊妙计都是一个可执行的算法。  
  6.     public void operate();  
  7.   
  8. }  

然后再写三个实现类,有三个妙计嘛:

妙计一:初到吴国:

[java]  view plain copy print ?
  1. /** 
  2.  * 找乔国老帮忙,使孙权不能杀刘备。 
  3.  */  
  4. public class BackDoor implements IStrategy {  
  5.   
  6.     @Override  
  7.     public void operate() {  
  8.         System.out.println("找乔国老帮忙,让吴国太给孙权施加压力,使孙权不能杀刘备...");  
  9.     }  
  10.   
  11. }  

妙计二:求吴国太开个绿灯,放行:

[java]  view plain copy print ?
  1. /** 
  2.  * 求吴国太开个绿灯。 
  3.  */  
  4. public class GivenGreenLight implements IStrategy {  
  5.   
  6.     @Override  
  7.     public void operate() {  
  8.         System.out.println("求吴国太开个绿灯,放行!");  
  9.   
  10.     }  
  11.   
  12. }  

妙计三:孙夫人断后,挡住追兵:

[java]  view plain copy print ?
  1. /** 
  2.  * 孙夫人断后,挡住追兵。 
  3.  */  
  4. public class BackEnemy implements IStrategy {  
  5.   
  6.     @Override  
  7.     public void operate() {  
  8.         System.out.println("孙夫人断后,挡住追兵...");  
  9.   
  10.     }  
  11.   
  12. }  

好了,大家看看,三个妙计是有了,那需要有个地方放妙计啊,放锦囊里:

[java]  view plain copy print ?
  1. public class Context {  
  2.   
  3.     private IStrategy strategy;  
  4.   
  5.     // 构造函数,要你使用哪个妙计  
  6.     public Context(IStrategy strategy) {  
  7.         this.strategy = strategy;  
  8.     }  
  9.   
  10.     public void operate() {  
  11.         this.strategy.operate();  
  12.     }  
  13.   
  14. }  

然后就是赵云雄赳赳的揣着三个锦囊去江东使用

[java]  view plain copy print ?
  1. public class ZhaoYun {  
  2.   
  3.     /** 
  4.      * 赵云出场了,他根据诸葛亮给他的交代,依次拆开妙计 
  5.      */  
  6.     public static void main(String[] args) {  
  7.         Context context;  
  8.   
  9.         // 刚到吴国的时候拆开第一个  
  10.         System.out.println("----------刚刚到吴国的时候拆开第一个---------------");  
  11.         context = new Context(new BackDoor());  
  12.         context.operate();// 拆开执行  
  13.   
  14.         // 当刘备乐不思蜀时,拆开第二个  
  15.         System.out.println("----------刘备乐不思蜀,拆第二个了---------------");  
  16.         context = new Context(new GivenGreenLight());  
  17.         context.operate();// 拆开执行  
  18.   
  19.         // 孙权的小追兵了,咋办?拆开第三个锦囊  
  20.         System.out.println("----------孙权的小追兵了,咋办?拆开第三个锦囊---------------");  
  21.         context = new Context(new BackEnemy());  
  22.         context.operate();// 拆开执行  
  23.     }  
  24.   
  25. }  

就这三招,搞得的周郎是“赔了夫人又折兵”呀!这就是策略模式,高内聚低耦合的特点也表现出来了,还有一个就是扩展性,也就是OCP原则,策略类可以继续添加下去气,只是修改Context.java就可以了。

六. 应用实例3:(布局管理器)

在 Java 语言中对策略模式的应用是很多的,我们这里举个布局管理器的例子。在java.awt 类库中有很多种设定好了的Container 对象的布局格式,这些格式你可以在创建软件界面的时候使用到。如果不使用策略模式,那么就没有了对布局格式扩展的可能,因为你要去修改Container 中的方法,去让它知道你这种布局格式,这显然是不可行的。

 

让我们来看看 java 源码中的实现吧。先来看看参与的类和他们扮演的角色吧。

布局管理器接口的代码:

[java]  view plain copy print ?
  1. public interface LayoutManager {  
  2.     void addLayoutComponent(String name, Component comp);  
  3.   
  4.     Dimension minimumLayoutSize(Container parent);  
  5.   
  6.     void layoutContainer(Container parent);  
  7. }  

LayoutManager FlowLayout 就是具体的策略,代码不在

[java]  view plain copy print ?
  1. public class FlowLayout implements LayoutManager, java.io.Serializable   

 

[java]  view plain copy print ?
  1. public class GridLayout implements LayoutManager, java.io.Serializable   

Container

[java]  view plain copy print ?
  1. public class Container extends Component {  
  2.       
  3.     LayoutManager layoutMgr;//对布局管理器接口的引用  
  4.   
  5.     public LayoutManager getLayout() {  
  6.         return layoutMgr;  
  7.     }  
  8.   
  9.     public void setLayout(LayoutManager mgr) {  
  10.         layoutMgr = mgr;  
  11.         if (valid) {  
  12.             invalidate();  
  13.         }  
  14.     }  
  15. }  

可以看到,Container 根本就不关心你使用的是什么具体的布局管理器,这样也就使得Container 不会随着布局管理器的增多而修改本身。所以说策略模式是对变化的封装。

参考:

http://yangguangfu.iteye.com/blog/815107

http://www.cnblogs.com/wangjq/archive/2012/07/03/2570344.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值