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

来源:互联网 发布:知乎禁止转载如何复制 编辑:程序博客网 时间:2024/06/18 14:11

策略模式

一. 概述

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

二. 模式解读

2.1 策略模式的一般化类图

2.2 模式中的角色

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

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

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

2.3、代码结构

Strategy

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

具体策略类A

[java] view plaincopyprint?
  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 plaincopyprint?
  1. public class ConcreteStrategeB implements Strategy {  
  2.   
  3.     @Override  
  4.     public void algorithm() {  
  5.         System.out.println("算法B中的实现");  
  6.   
  7.     }  
  8.   
  9. }  

上下文类

[java] view plaincopyprint?
  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 plaincopyprint?
  1. public interface SortStratege {  
  2.     // 排序  
  3.     public int[] Sort(int[] array);  
  4. }  

冒泡排序策略

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

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

妙计一:初到吴国:

[java] view plaincopyprint?
  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 plaincopyprint?
  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 plaincopyprint?
  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 plaincopyprint?
  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 plaincopyprint?
  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 plaincopyprint?
  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 plaincopyprint?
  1. public class FlowLayout implements LayoutManager, java.io.Serializable   

 

[java] view plaincopyprint?
  1. public class GridLayout implements LayoutManager, java.io.Serializable   

Container

[java] view plaincopyprint?
  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
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 费雪小火车不走怎么办 宝宝睡觉要开灯怎么办 门上有人做记号怎么办 颜料粘上衣服洗不掉怎么办 半夜有小偷开锁怎么办 幼儿园人数较多怎么办 附近幼儿园拖班招满了怎么办 6个月大宝宝拉肚子怎么办 婴儿容易吐奶怎么办 新生儿睡眠时间颠倒怎么办 婴儿睡觉黑白颠倒怎么办 婴儿黑白颠倒了怎么办 宝宝肠粘膜受损怎么办 dnf会卡换装怎么办? 孩子不讲理蛮横怎么办 孩子不爱上学了怎么办 幼儿园孩子不爱上学怎么办 额头撞肿了怎么办 两岁半宝宝说话晚怎么办 1岁宝宝拉肚子怎么办? 小孩嗓子老哑怎么办 小孩嗓子经常哑怎么办 小孩子一年级成绩差怎么办 小孩子一年级学习成绩差怎么办 楼上有孩子扰民怎么办 隔壁小孩太吵怎么办 楼上孩子太吵怎么办 泰国贴纸签小孩怎么办 六个月宝宝近视怎么办 孩子视力低应该怎么办 儿童视力低常怎么办 视力储备值低怎么办 六个月宝宝远视怎么办 婴儿喜欢舔衣服怎么办 一岁半宝宝抵抗力差怎么办 两个月宝宝打嗝怎么办 衣服买大一码怎么办 8岁儿童头汗多怎么办 新生儿肛门红了怎么办 40天新生儿发烧怎么办 十天婴儿发烧怎么办