【设计模式】之 Strategy 模式

Motivation

在软件的构建当中,某些对象使用的算法可能多种多样,并且需要经常改变,如果将这些算法都硬编码到对象中,将会使对象变得异常复杂,而且有时支持不使用的算法也是一种性能负担。
如何在运行的时候根据需要透明的更改对象的算法,将算法与对象本身解耦,从而避免这样的问题。

Intent

定义一系列算法,把它们一个个封装起来,并且使它们可以相互替换。该模式使得算法可独立于使用它的客户而变化。
策略模式相当于"可插入式(Pluggable)的算法"。允许客户端动态决定现在用什么算法。

Structure

【设计模式】之 Strategy 模式

把行为和环境分割开来。环境类负责维持和查询行为类,各种算法则在具体策略类(ConcreteStrategy)中提供,作为一个抽象策略类的子类。由于算法和环境独立开来,算法的增减、修改都不会影响环境和客户端。当出现新的算法出现时,只需要实现新的策略类,并在客户端登记即可。

  • 环境(Context)角色持有一个算法策略Strategy类的引用 和 contextInterface()方法,方法内调用算法策略接口。
    可以在构造函数中或者写一个SetStrategy函数(如下实例),给context类的Strategy成员赋值(即客户端决定实例化那个ConcreteStrategy,用哪种算法)
    contextInterface()例如下面的 public void Sort(){  //调用算法策略接口 sortstrategy.Sort(list);//...}
  • 抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
    declares an interface common to all supported algorithms. Context uses this interface to call the algorithm defined by a ConcreteStrategy
  • 具体策略(ConcreteStrategy)角色:包装了相关的算法或行为。
    strategy structure

     

    实例
    This sample demonstrates the Strategy pattern which encapsulates sorting algorithms in the form of sorting objects.
    This allows clients to dynamically change sorting strategies including Quicksort, Shellsort, and Mergesort.

  • Strategy  (SortStrategy)
  • ConcreteStrategy  (QuickSort, ShellSort, MergeSort)

    implements the algorithm using the Strategy interface

  • Context  (SortedList)
    1. is configured with a ConcreteStrategy object

    2. maintains a reference to a Strategy object
    3. may define an interface that lets Strategy access its data.

    排序算法 策略模式

     

    .NET中的策略模式

    ArrayList的排序
    ArrayList.Sort() 对于自定义的特殊对象,非字符串序列,要传入实现了ICompare的对象作为参数

    .NET中策略模式

     

    反射实现动态可配置算法(对《大话》例子的思考)

    思考:简单工厂模式实现的商场收银系统有什么劣势呢?

    根据用户在ComboBox的选择,用工厂创建相应的算法对象,然后使用。看起来很好的方案。

    //利用简单工厂模式根据下拉选择框,生成相应的对象
    CashSuper csuper = CashFactory.createCashAccept(cbxType.SelectedItem.ToString());
    double totalPrices = 0d;
    //通过多态,可以得到收取费用的结果
    "实收" = csuper.acceptCash(“应收");

    可以看出因为工厂模式是创建型的,所以一定要创建出算法对象,程序要持有这个对象,调用对象内的算法,才能实现功能。
    我们知道,每个模式都是适用一定的场合的,在这个场合中,因为剧烈变化的是算法,试想,如果算法里包括了积分计算,因为积分政策的变化,所以我们需要改算法。因此就需要重新编译我们的工厂类,重新给客户部署。似乎有些不太方便。

    而策略模式正是解决这种问题的,将算法一个个封装起来,并且使它们可以相互替换。
    但是简单的策略模式,客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,简单策略模式只适用于客户端知道所有的算法或行为的情况。
    而没有反射,因为你要Hardcode,就利用不了算法相互替换的功能。

  • 技巧一:使用XML文件或者数据库将算法名称和comboBox绑定

    算法配置XML文件

     

    利用程序读取这个配置文件,实现和Combobox的绑定

    读取XML内信息,将算法名称和ComboBox绑定

     

  • 技巧二: 反射实现动态创建

    (基类)Assembly.Load("程序集名称").CreateInstance("名称空间.子类名称")

    反射

     

  • 你可能感兴趣的:(strategy)