设计模式-行为型-策略模式
策略模式(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)系统要求使用算法的客户不应该知道其操作的数据时,可使用策略模式来隐藏与算法相关的数据结构。
5)多个类只区别在表现行为不同,可以使用策略模式,在运行时动态选择具体要执行的行为。
策略模式与工厂模式的区别?
从结构上看,策略模式和工厂模式都是子类继承抽象父类,通过传入参数到容器类(工厂模式的factory类,策略模式的Content类),选择对应的类进行行为操作。但是我们都知道工厂模式是创建型设计模式,而策略模式则是行为型设计模式。那两者到底有什么区别呢?
1)工厂模式是用来创建对象,策略模式是让一个对象在许多行为中选择一种行为。
2)关注点不一样,一个关注对象的创建,一个关注的是行为封装。
3)解决不同的问题:工厂模式是创建型的设计模式,它接受指令,创建出符合要求的实例;它主要解决的是资源的统一分发,将对象的创建完全独立出来,让对象的创建和具体的使用客户无关。主要应用在多数据库选择,类库文件加载等。策略模式是为了解决的是策略的切换与扩展,更简洁的说是定义策略族,分别封装起来,让他们之间可以相互替换,策略模式让策略的变化独立于使用策略的客户。
4)工厂相当于黑盒子,策略相当于白盒子。
策略模式与桥接模式的区别?
在桥接模式中,Abstraction通过聚合的方式引用Implementor。策略模式中,Context也使用聚合的方式引用Strategy抽象接口。从两者的结构图可以看出,在这两种模式中,都存在一个对象使用聚合的方式引用另一个对象的抽象接口的情况,而且该抽象接口的实现可以有多种并且可以替换。可以说两者在表象上都是调用者与被调用者之间的解耦,以及抽象接口与实现的分离。但两者存在一定的区别:
1)在形式上,在桥接模式中不仅Implementor具有变化(ConcreateImplementior),而且Abstraction也可以发生变化(RefinedAbstraction),而且两者的变化是完全独立的,RefinedAbstraction与ConcreateImplementior之间松散耦合,它们仅仅通过Abstraction与Implementor之间的关系联系起来。而在策略模式中,并不考虑Context的变化,只有算法的可替代性。
2)在语意上,桥接模式强调Implementor接口仅提供基本操作,而Abstraction则基于这些基本操作定义更高层次的操作。而策略模式强调Strategy抽象接口的提供的是一种算法,一般是无状态、无数据的,而Context则简单调用这些算法完成其操作。
3)桥接模式中不仅定义Implementor的接口而且定义Abstraction的接口,Abstraction的接口不仅仅是为了与Implementor通信而存在的,这也反映了结构型模式的特点:通过继承、聚合的方式组合类和对象以形成更大的结构。在策略模式中,Startegy和Context的接口都是两者之间的协作接口,并不涉及到其它的功能接口,所以它是行为模式的一种。行为模式的主要特点就是处理的是对象之间的通信方式,往往是通过引入中介者对象将通信双方解耦,在这里实际上就是将Context与实际的算法提供者解耦。
所以相对策略模式,桥接模式要表达的内容要更多,结构也更加复杂。桥接模式表达的主要意义其实是接口隔离的原则,即把本质上并不内聚的两种体系区别开来,使得它们可以松散的组合,而策略在解耦上还仅仅是某一个算法的层次,没有到体系这一层次。从结构图中可以看到,策略的结构是包容在桥接结构中的,桥接中必然存在着策略模式,Abstraction与Implementor之间就可以认为是策略模式,但是桥接模式一般Implementor将提供一系列的成体系的操作,而且Implementor是具有状态和数据的静态结构。而且桥接模式Abstraction也可以独立变化。
参考:https://blog.csdn.net/donnie88888888/article/details/52751328
https://blog.csdn.net/basycia/article/details/50478245
http://www.blogjava.net/wangle/archive/2007/04/25/113545.html