策略模式(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、 策略模式造成很多的策略類,每個具體策略類都會產生一個新類。有時候可以通過把依賴於環境的狀態保存到客戶端里面,而將策略類設計成可共享的,這樣策略類實例可以被不同客戶端使用。換言之,可以使用
享元模式來減少對象的數量。