策略模式(Strategy Pattern)
一个类的行为或其算法可以在运行时更改,这种设计模式最核心点就是封装算法的变化,让他们能相互替换。
废话不多说,先上需求:商场结账要一个统计商品的购买总价,并在原来价格的基础上出现打折、返利等优惠活动。
策略模式类图
几个策略方法继承于同一个抽象类,他们都通过context这个上下文接口进行实例化 。
CashSuper策略抽象类
abstract class CashSuper { public constructor() { } public abstract acceptCash(money: number); //优惠策略的抽象方法 }
CashNormal正常策略类
class CashNormal extends CashSuper { public constructor() { super(); } public acceptCash(money: number): number { return money; } }
CashRebate打折策略类
class CashRebate extends CashSuper { private moneyRebate: number = 1; public constructor(moneyRebate: number) { super(); this.moneyRebate = moneyRebate; } public acceptCash(money: number): number { money = money * this.moneyRebate; return money; } }
CashReturn返利策略类
class CashReturn extends CashSuper { private moneyCondition: number = 0; private moneyReturn: number = 0; public constructor(moneyCondition: number, moneyReturn: number) { super(); this.moneyCondition = moneyCondition; this.moneyReturn = moneyReturn; } public acceptCash(money: number): number { if (money >= this.moneyCondition) money = money - this.moneyReturn * Math.floor(money / this.moneyCondition); return money; } }
CashContext策略上下文接口
class CashContext { public cs: CashSuper = null public constructor(type: string) { switch(type) { case "Normal": let cn: CashNormal = new CashNormal(); this.cs = cn; break; case "Rebate": let cb: CashRebate = new CashRebate(0.8); this.cs = cb; break; case "Return": let ct: CashReturn = new CashReturn(300, 100); this.cs = ct; break; } } public GetResult(money: number): number { return this.cs.acceptCash(money); } }
p.s : 以上代码为策略模式与简单工厂的结合,目的是为了调用时候只引用CashContext一个类,使算法与客户端完全分离,降低耦合。但这样处理一定程度上也违背了开闭原则,进一步改进可采用反射技术。
客户端测试
let total: number = 1000; //购买原价 let cc_1: CashContext = new CashContext("Normal"); // 原价 let cc_2: CashContext = new CashContext("Return"); // 返利策略 let cc_3: CashContext = new CashContext("Rebate"); // 打折策略 total = cc_1.GetResult(total); // 1000 total = cc_2.GetResult(total); // 1000 -> 700 total = cc_3.GetResult(total); // 700 -> 560
优缺点
优点:
1、
策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码转移到父类里面,从而避免重复的代码。
2、
策略模式提供了可以替换继承关系的办法。继承可以处理多种算法或行为。如果不是用策略模式,那么使用算法或行为的环境类就可能会有一些子类,每一个子类提供一个不同的算法或行为。但是,这样一来算法或行为的使用者就和算法或行为本身混在一起。决定使用哪一种算法或采取哪一种行为的逻辑就和算法或行为的逻辑混合在一起,从而不可能再独立演化。继承使得动态改变算法或行为变得不可能。
3、
使用策略模式可以避免使用多重条件转移语句。多重转移语句不易维护,它把采取哪一种算法或采取哪一种行为的逻辑与算法或行为的逻辑混合在一起,统统列在一个多重转移语句里面,比使用继承的办法还要原始和落后。
缺点:
1、客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道所有的算法或行为的情况。
2、 策略模式造成很多的策略类,每个具体策略类都会产生一个新类。有时候可以通过把依赖于环境的状态保存到客户端里面,而将策略类设计成可共享的,这样策略类实例可以被不同客户端使用。换言之,可以使用
享元模式来减少对象的数量。