一、 策略(Strategy)模式

策略模式的用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。

假 设现在要设计一个贩卖各类书籍的电子商务网站的购物车(Shopping Cat)系统。一个最简单的情况就是把所有货品的单价乘上数量,但是实际情况肯定比这要复杂。比如,本网站可能对所有的教材类图书实行每本一元的折扣;对 连环画类图书提供每本7%的促销折扣,而对非教材类的计算机图书有3%的折扣;对其余的图书没有折扣。由于有这样复杂的折扣算法,使得价格计算问题需要系 统地解决。

使用策略模式可以把行为和环境分割开来。环境类负责维持和查询行为类,各种算法则在具体策略类 (ConcreteStrategy)中提供。由于算法和环境独立开来,算法的增减、修改都不会影响环境和客户端。当出现新的促销折扣或现有的折扣政策出 现变化时,只需要实现新的策略类,并在客户端登记即可。策略模式相当于"可插入式(Pluggable)的算法"。

二、 策略模式的结构

策略模式是对算法的包装,是把使用算法的责任和算法本身分割开,委派给不同的对象管理。策略模式通常把一个系列的算法包装到一系列的策略类里面,作为一个抽象策略类的子类。用一句话来说,就是:"准备一组算法,并将每一个算法封装起来,使得它们可以互换。"

策略又称做政策(Policy)模式【GOF95】。下面是一个示意性的策略模式结构图:

这个模式涉及到三个角色:

  • 环境(Context)角色:持有一个Strategy类的引用。
  • 抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
  • 具体策略(ConcreteStrategy)角色:包装了相关的算法或行为。

三、 示意性源代码

// Strategy pattern -- Structural example  
using System;

// "Strategy"
abstract class Strategy
{
  // Methods
  abstract public void AlgorithmInterface();
}

// "ConcreteStrategyA"
class ConcreteStrategyA : Strategy
{
  // Methods
  override public void AlgorithmInterface()
  {
    Console.WriteLine("Called ConcreteStrategyA.AlgorithmInterface()");
  }
}

// "ConcreteStrategyB"
class ConcreteStrategyB : Strategy
{
  // Methods
  override public void AlgorithmInterface()
  {
    Console.WriteLine("Called ConcreteStrategyB.AlgorithmInterface()");
  }
}

// "ConcreteStrategyC"
class ConcreteStrategyC : Strategy
{
  // Methods
  override public void AlgorithmInterface()
  {
    Console.WriteLine("Called ConcreteStrategyC.AlgorithmInterface()");
  }
}

// "Context"
class Context
{
  // Fields
  Strategy strategy;

  // Constructors
  public Context( Strategy strategy )
  {
    this.strategy = strategy;
  }

  // Methods
  public void ContextInterface()
  {
    strategy.AlgorithmInterface();
  }
}

/// <summary>
/// Client test
/// </summary>
public class Client
{
  public static void Main( string[] args )
  {
    // Three contexts following different strategies
    Context c = new Context( new ConcreteStrategyA() );
    c.ContextInterface();

    Context d = new Context( new ConcreteStrategyB() );
    d.ContextInterface();

    Context e = new Context( new ConcreteStrategyC() );
    e.ContextInterface();
  }
}

四、 何时使用何种具体策略角色

在学习策略模式时,学员常问的一个问题是:为什么不能从策略模式中看出哪一个具体策略适用于哪一种情况呢?

答案非常简单,策略模式并不负责做这个决定。换言之,应当由客户端自己决定在什么情况下使用什么具体策略角色。策略模式仅仅封装算法,提供新算法插入到已有系统中,以及老算法从系统中"退休"的方便,策略模式并不决定在何时使用何种算法。

五、 一个实际应用策略模式的例子

下面的例子利用策略模式在排序对象中封装了不同的排序算法,这样以便允许客户端动态的替换排序策略(包括Quicksort、Shellsort和Mergesort)。

// Strategy pattern -- Real World example  
using System;
using System.Collections;

// "Strategy"
abstract class SortStrategy
{
  // Methods
  abstract public void Sort( ArrayList list );
}

// "ConcreteStrategy"
class QuickSort : SortStrategy
{
  // Methods
  public override void Sort(ArrayList list )
  {
    list.Sort(); // Default is Quicksort
    Console.WriteLine("QuickSorted list ");
  }
}

// "ConcreteStrategy"
class ShellSort : SortStrategy
{
  // Methods
  public override void Sort(ArrayList list )
  {
    //list.ShellSort();
    Console.WriteLine("ShellSorted list ");
  }
}

// "ConcreteStrategy"
class MergeSort : SortStrategy
{
  // Methods
  public override void Sort( ArrayList list )
  {
    //list.MergeSort();
    Console.WriteLine("MergeSorted list ");
  }
}

// "Context"
class SortedList
{
  // Fields
  private ArrayList list = new ArrayList();
  private SortStrategy sortstrategy;

  // Constructors
  public void SetSortStrategy( SortStrategy sortstrategy )
  {
    this.sortstrategy = sortstrategy;
  }

  // Methods
  public void Sort()
  {
    sortstrategy.Sort( list );
  }

  public void Add( string name )
  {
    list.Add( name );
  }

  public void Display()
  {
    foreach( string name in list )
      Console.WriteLine( " " + name );
  }
}

/// <summary>
/// StrategyApp test
/// </summary>public class StrategyApp{  public static void Main( string[] args )  {    // Two contexts following different strategies    SortedList studentRecords = new SortedList( );    studentRecords.Add( "Samual" );    studentRecords.Add( "Jimmy" );    studentRecords.Add( "Sandra" );    studentRecords.Add( "Anna" );    studentRecords.Add( "Vivek" );    studentRecords.SetSortStrategy( new QuickSort() );    studentRecords.Sort();    studentRecords.Display();  }}

六、 在什么情况下应当使用策略模式

在下面的情况下应当考虑使用策略模式:

1. 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。

2. 一 个系统需要动态地在几种算法中选择一种。那么这些算法可以包装到一个个的具体算法类里面,而这些具体算法类都是一个抽象算法类的子类。换言之,这些具体算 法类均有统一的接口,由于多态性原则,客户端可以选择使用任何一个具体算法类,并只持有一个数据类型是抽象算法类的对象。

3. 一个系统的算法使用的数据不可以让客户端知道。策略模式可以避免让客户端涉及到不必要接触到的复杂的和只与算法有关的数据。

4. 如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。此时,使用策略模式,把这些行为转移到相应的具体策略类里面,就可以避免使用难以维护的多重条件选择语句,并体现面向对象设计的概念。

七、 策略模式的优点和缺点

策略模式有很多优点和缺点。它的优点有:

1. 策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码移到父类里面,从而避免重复的代码。

2. 策 略模式提供了可以替换继承关系的办法。继承可以处理多种算法或行为。如果不是用策略模式,那么使用算法或行为的环境类就可能会有一些子类,每一个子类提供 一个不同的算法或行为。但是,这样一来算法或行为的使用者就和算法或行为本身混在一起。决定使用哪一种算法或采取哪一种行为的逻辑就和算法或行为的逻辑混 合在一起,从而不可能再独立演化。继承使得动态改变算法或行为变得不可能。

3. 使用策略模式可以避免使用多重条件转移语句。多重转移语句不易维护,它把采取哪一种算法或采取哪一种行为的逻辑与算法或行为的逻辑混合在一起,统统列在一个多重转移语句里面,比使用继承的办法还要原始和落后。

策略模式的缺点有:

1. 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道所有的算法或行为的情况。

2. 策略模式造成很多的策略类。有时候可以通过把依赖于环境的状态保存到客户端里面,而将策略类设计成可共享的,这样策略类实例可以被不同客户端使用。换言之,可以使用享元模式来减少对象的数量。

八、 其它

策 略模式与很多其它的模式都有着广泛的联系。Strategy很容易和Bridge模式相混淆。虽然它们结构很相似,但它们却是为解决不同的问题而设计的。 Strategy模式注重于算法的封装,而Bridge模式注重于分离抽象和实现,为一个抽象体系提供不同的实现。Bridge模式与Strategy模 式都很好的体现了"Favor composite over inheritance"的观点。

推荐大家读一读《IoC 容器和Dependency Injection 模式》,作者Martin Fowler。网上可以找到中文版的PDF文件。为策略模式的实施提供了一个非常好的方案。


参考文献:
阎宏,《Java与模式》,电子工业出版社
[美]James W. Cooper,《C#设计模式》,电子工业出版社
[美]Alan Shalloway  James R. Trott,《Design Patterns Explained》,中国电力出版社
[美]Robert C. Martin,《敏捷软件开发-原则、模式与实践》,清华大学出版社
[美]Don Box, Chris Sells,《.NET本质论 第1卷:公共语言运行库》,中国电力出版社

转载于:https://www.cnblogs.com/freebird92/p/4283783.html

[转]设计模式(22)-Strategy Pattern相关推荐

  1. 策略设计模式(Strategy Pattern)[论点:概念、组成角色、相关图示、示例代码、适用场景]

    文章目录 概念 组成角色 相关图示 示例代码 适用场景 概念 策略模式(Strategy Pattern)是一种行为设计模式,它定义了一系列的算法,并将每一个算法封装起来,使它们可以相互替换.策略模式 ...

  2. 解读设计模式----策略模式(Strategy Pattern)

    一.模式概述      策略模式(Strategy Pattern)在外形上与状态模式很相似,但在意图上有些不同.其意图是使这些算法可以相互替换,并提供一种方法来选择最合适的算法.       在我应 ...

  3. 二十四种设计模式:策略模式(Strategy Pattern)

    策略模式(Strategy Pattern) 介绍 定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换.本模式使得算法的变化可独立于使用它的客户. 示例 有一个Message实体类,对它的操 ...

  4. 行为型设计模式(5)—— 策略模式(Strategy Pattern)

    文章目录 1.概述 2.实例 2.1 丑陋的设计 2.2 合适的设计 3.小结 参考文献 1.概述 使用设计模式可以提高代码的可复用性.可扩充性和可维护性.策略模式(Strategy Pattern) ...

  5. 设计模式之策略模式(Strategy Pattern)

    什么是策略模式? 策略模式是23种经典是设计模式之一,它是一种行为型模式.也是我们非常常见的一种模式,它通常解决的是软件中多种算法之间的行为切换,通俗来讲,就是解决我们程序中多个if...else.s ...

  6. 设计模式(一):“穿越火线”中的“策略模式”(Strategy Pattern)

    在前段时间呢陆陆续续的更新了一系列关于重构的文章.在重构我们既有的代码时,往往会用到设计模式.在之前重构系列的博客中,我们在重构时用到了"工厂模式"."策略模式" ...

  7. 【Java设计模式】Java设计模式之(十五)策略模式(Strategy Pattern)

    本文目录 一.策略模式介绍 1.1 含义 1.2 适用场景 1.3 主要解决 1.4 应用实例 1.5 优缺点 二.策略模式实现 2.1 类图 2.2 代码实现 第一个案例:策略模式代码实现 第二个案 ...

  8. java 23 种设计模式-23-java 策略模式(Strategy Pattern)

    目录 目录 策略模式 实际案例 定义 测试 实现方式 UML & Code UML Code 系列导航 策略模式 在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运 ...

  9. 8.6 GOF设计模式四: 策略模式… Strategy Pattern

    策略模式- Strategy Pattern  在POS系统中,有时需要实行价格优惠, 该如何处理?  对普通客户或新客户报全价  对老客户统一折扣5%  对大客户统一折扣10%  注:课件 ...

最新文章

  1. oracle 表查看依赖,oracle – 表依赖的递归查询不会像我想的那样递归
  2. 数据库路由中间件MyCat - 源代码篇(15)
  3. vue.js快速入门
  4. mysql删除数据表show_数据库与表显示、创建、删除
  5. 6、Qt Meta Object system 学习
  6. oracle支持非关系数据库,Oracle-03: 关系型数据库和非关系的数据库的各自优缺点与区别...
  7. python3怎么使用mnist_loader_Python读取mnist
  8. 使用lua实现nginx rewrite
  9. 32位jdk_详解在Linux系统中安装JDK
  10. 亲身经历:2018年深圳保洁员工资时薪75,月薪不清楚
  11. 【路径规划】基于matlab多种算法无人机路径规划【含Matlab源码 1263期】
  12. 计算机网络技术教研活动,(2012.09.27)计算机网络技术专业教研活动(文本).doc...
  13. 小甲鱼Python教程,截图+代码+学习笔记,Python入门【10000字】【原创】
  14. 个人技术总结——Unity中角色动画制作及动画切换逻辑的实现
  15. 动态规划 leetcode-714 最佳买卖股票时机含手续费
  16. Python-docx生成word文档
  17. [RS] 基础概念区分:DN-辐射率-反射率
  18. Python基础:break语句知识详解
  19. SQLServer中uniqueidentifier数据类型理解
  20. 关于PR安装在D盘初始化时闪退,加载到optical的时候PR直接闪退

热门文章

  1. python操作excel-python 操作excel
  2. Jupyter notebook导出的html文件不能够正确显示图片
  3. windows的.bat批处理文件运行Python脚本程序
  4. resultMap和resultType的区别
  5. 开源大数据引擎:Greenplum 数据库架构分析
  6. rest-framework 分页器
  7. HDU2034 人见人爱A-B
  8. 获取微软产品下载链接
  9. python ---Pandas时间序列:生成指定范围的日期
  10. 软件工程--团队作业4