策略模式(Strategy):
策略模式是对算法的包装,是把使用算法的责任和算法本身分割开来,委派给不同的对象管理。策略模式通常把一个系列的算法包装到一系列的策略类里面,作为一个抽象策略类的子类。用一句话来说,就是:“准备一组算法,并将每一个算法封装起来,使得它们可以互换”。
策略模式的角色:
1)环境类(Context):采用组合或聚合的方式维护一个对Strategy对象的引用。
2)抽象策略类(Strategy):定义所有支持的算法的公共接口。Context使用这个接口来调用某ConcreteStrategy定义的算法。
3)具体策略类(ConcreteStrategy):实现Strategy接口。
案例:
某商场销售系统采用三种收费逻辑:正常收费;返现收费(满300返20);打折收费(打8折)。
1 internal class Program 2 { 3 private static void Main(string[] args) 4 { 5 CashContext cashContext = new CashContext(new CashNormal()); 6 Console.WriteLine(cashContext.GetResult(200)); 7 CashContext cashContext2 = new CashContext(new CashRebate(0.8)); 8 Console.WriteLine(cashContext2.GetResult(200)); 9 CashContext cashContext3 = new CashContext(new CashReturn(300, 20)); 10 Console.WriteLine(cashContext3.GetResult(300)); 11 } 12 } 13 14 /// <summary> 15 /// 环境类Context 16 /// </summary> 17 public class CashContext 18 { 19 private CashSuper cs; 20 21 public CashContext(CashSuper cashSuper) 22 { 23 this.cs = cashSuper; 24 } 25 26 public double GetResult(double money) 27 { 28 if (cs != null) 29 { 30 return cs.AcceptCash(money); 31 } 32 return 0; 33 } 34 } 35 36 /// <summary> 37 /// 收费系统,相当于Strategy 38 /// </summary> 39 public interface CashSuper 40 { 41 double AcceptCash(double money); 42 } 43 44 /// <summary> 45 /// 正常收费 46 /// </summary> 47 public class CashNormal : CashSuper 48 { 49 public double AcceptCash(double money) 50 { 51 return money; 52 } 53 } 54 55 /// <summary> 56 /// 打折收费 57 /// </summary> 58 public class CashRebate : CashSuper 59 { 60 private double moneyRebate = 1d; 61 62 public CashRebate(double moneyRebate) 63 { 64 this.moneyRebate = moneyRebate; 65 } 66 67 public double AcceptCash(double money) 68 { 69 return money * moneyRebate; 70 } 71 } 72 73 /// <summary> 74 /// 返现收费 75 /// </summary> 76 public class CashReturn : CashSuper 77 { 78 private double moneyCondition = 0.0d; 79 private double moneyReturn = 0.0d; 80 81 public CashReturn(double moneyCondition, double moneyReturn) 82 { 83 this.moneyCondition = moneyCondition; 84 this.moneyReturn = moneyReturn; 85 } 86 87 public double AcceptCash(double money) 88 { 89 double result = money; 90 if (money >= moneyCondition) 91 result = money - Math.Floor(money / moneyCondition) * moneyReturn; 92 return result; 93 } 94 }
策略模式的优缺点:
优点:
1)策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码转移到父类里面,从而避免重复的代码。
2)策略模式提供了可以替换继承关系的办法。继承可以处理多种算法或行为。如果不是用策略模式,那么使用算法或行为的环境类就可能会有一些子类,每一个子类提供一个不同的算法或行为。但是,这样一来算法或行为的使用者就和算法或行为本身混在一起。决定使用哪一种算法或采取哪一种行为的逻辑就和算法或行为的逻辑混合在一起,从而不可能再独立演化。继承使得动态改变算法或行为变得不可能。
3)使用策略模式可以避免使用多重条件转移语句。多重转移语句不易维护,它把采取哪一种算法或采取哪一种行为的逻辑与算法或行为的逻辑混合在一起,统统列在一个多重转移语句里面,比使用继承的办法还要原始和落后。
缺点:
1)客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道所有的算法或行为的情况。
2)策略模式造成很多的策略类,每个具体策略类都会产生一个新类。有时候可以通过把依赖于环境的状态保存到客户端里面,而将策略类设计成可共享的,这样策略类实例可以被不同客户端使用。换言之,可以使用享元模式来减少对象的数量。
策略模式的应用场景:
1)一个系统需要动态地在几种算法中选择一种时,可将每个算法封装到策略类中。
2)一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现,可将每个条件分支移入它们各自的策略类中以代替这些条件语句。
3)系统中各算法彼此完全独立,且要求对客户隐藏具体算法的实现细节时。
4)系统要求使用算法的客户不应该知道其操作的数据时,可使用策略模式来隐藏与算法