转载:设计模式之——策略模式

什么是策略模式

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

策略模式的结构

  我们先观察策略模式(Strategy Pattern)的UML类图:

根据前面的类图我们可以知道策略模式由下面的几个部分组成:

  • 抽象策略类:所以策略子类的通用接口,通常由一个抽象类和接口来实现。
  • 具体策略类:实现了抽象策略类,包装的相关的算法和行为。
  • Context类:供客户代码调用,持有一个抽象策略类的引用,根据客户端不同的调用,返回不同的具体策略实例。

策略模式的优缺点

策略模式的优点:

  • 提供了一种替代继承的方法,而且既保持了继承的优点(代码重用)还比继承更灵活(算法独立,可以任意扩展)。
  • 避免程序中使用多重条件转移语句,使系统更灵活,并易于扩展。
  • 遵守大部分GRASP原则和常用设计原则,高内聚、低偶合。

策略模式的缺点:

  • 因为每个具体策略类都会产生一个新类,所以会增加系统需要维护的类的数量。

策略模式的代码实例

   根据商场打折、促销等,算法需要经常性的变动的场景来提供一个策略模式实现的一个收费程序。

 首先定义一个结算的抽象类(接口):

复制代码
1     /// <summary>
2     /// 现金收费抽象类
3     /// </summary>
4     abstract class CashSuper
5     {
6         //现金收取超类的抽象方法,收取现金,参数为原价,返回当前价。
7         public abstract double acceptCash(double money);
8     }
复制代码

然后根据打折、促销等不同的活动实现具体收费功能的子类

复制代码
 1     /// <summary>
 2     /// 正常收费子类
 3     /// </summary>
 4     class CashNormal:CashSuper
 5     {
 6         public override double acceptCash(double money)
 7         {
 8             return money;
 9         }
10     }
11 
12     /// <summary>
13     /// 打折子类
14     /// </summary>
15     class CashRebate:CashSuper
16     {
17         private double moneyRebate = 1d;
18         public CashRebate(string moneyRebate)
19         {
20             this.moneyRebate = double.Parse(moneyRebate);
21         }
22 
23         public override double acceptCash(double money)
24         {
25             return money * moneyRebate;
26         }
27     }
28 
29     /// <summary>
30     /// 返利子类
31     /// </summary>
32     class CashReturn:CashSuper
33     {
34         private double moneyCondition = 0.0d;
35         private double moneyReturn = 0.0d;
36 
37         /// <summary>
38         /// 返利子类构造方法
39         /// </summary>
40         /// <param name="moneyCondition">返利标准</param>
41         /// <param name="moneyReturn">返利值</param>
42         public CashReturn(string moneyCondition, string moneyReturn)
43         {
44             this.moneyCondition = double.Parse(moneyCondition);
45             this.moneyReturn = double.Parse(moneyReturn);
46         }
47 
48         public override double acceptCash(double money)
49         {
50             double result = money;
51 
52             if (money >= moneyCondition)
53                 result = money - Math.Floor(money / moneyCondition) * moneyReturn;
54 
55             return result;
56         }
57     }
复制代码

最后创建的是提供给客户端调用的Context类

复制代码
 1  class CashContext
 2     {
 3         CashSuper cs;
 4 
 5         public CashContext(string type)
 6         {
 7             //简单工厂构造函数,克服客户端需要知道所以算法子类的缺点(封装了变化)
 8             switch (type)
 9             {
10                 case "正常收费":
11                     cs = new CashNormal();
12                     break;
13                 case "满300返100":
14                     cs = new CashReturn("300", "100");
15                     break;
16                 case "打8折":
17                     cs = new CashRebate("0.8");
18                     break;
19             }
20         }
21 
22         //和简单工厂的不同之处
23         public double GetResult(double money)
24         {
25             return cs.acceptCash(money);
26         }
27     }
复制代码

客户代码调用,编译运行:

复制代码
1     CashContext csuper = new CashContext(cmbDiscount.SelectedItem.ToString());
2             double totalPrices = 0d;
3             totalPrices = csuper.GetResult(double.Parse(this.txtPrice.Text) * double.Parse(this.txtNumber.Text));
4 
5             this.lbxResult.Items.Add("单价:" + this.txtPrice.Text + " 数量:" + this.txtNumber.Text + " " + cmbDiscount.SelectedItem + " " + "合计" + totalPrices.ToString());
6 
7             total = total + totalPrices;
8             this.lblAmount.Text = total.ToString();
复制代码

策略模式和简单工厂的区别

  通过对比简单工厂和策略模式的UML类图我们可以发现二者结构比较相似:

我们可以发现使用策略模式实现的都可以使用简单工厂来实现,二者都是通过使用继承以多态的形式来实现的。在产品构造多次重叠,并且在不同时刻应用不同的规则(算法)时使用策略模式比较合适。我们可以发现简单工厂只是通过一个静态的类方法来创建不同的子类,但是在策略模式中除了通过多态创建不同的算法子类,还有一个调用子类示例函数的一个成员方法(Context类中),所以在客户端中我们只需要获取一个Context实例时候,然后通过直接调用它的实例方法来间接调用子类的成员方法就可以了(构造函数使用简单工厂来实现);但是在简单工厂中我们除了通过调用工厂类的静态方法获取产品子类的实例,还要直接调用子类的成员方法。 

转自作者:晴天猪

出处:http://www.cnblogs.com/IPrograming 

本文版权归上述作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

原文地址:https://www.cnblogs.com/suifengbingzhu/p/2648311.html