【設(shè)計(jì)模式(二)】策略模式——商場(chǎng)打折計(jì)算系統(tǒng)

策略模式(Strategy Pattern)
一個(gè)類的行為或其算法可以在運(yùn)行時(shí)更改,這種設(shè)計(jì)模式最核心點(diǎn)就是封裝算法的變化,讓他們能相互替換。
廢話不多說,先上需求:商場(chǎng)結(jié)賬要一個(gè)統(tǒng)計(jì)商品的購買總價(jià),并在原來價(jià)格的基礎(chǔ)上出現(xiàn)打折、返利等優(yōu)惠活動(dòng)。
策略模式類圖

幾個(gè)策略方法繼承于同一個(gè)抽象類,他們都通過context這個(gè)上下文接口進(jìn)行實(shí)例化 。
?
CashSuper策略抽象類
abstract class CashSuper {
? ?public constructor() {}
? ?public abstract acceptCash(money: number); ?//優(yōu)惠策略的抽象方法
}
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 : 此為策略模式與簡(jiǎn)單工廠的結(jié)合,目的是為了調(diào)用時(shí)候只引用CashContext一個(gè)類,使算法與客戶端完全分離,降低耦合。但這樣處理一定程度上也違背了開閉原則,進(jìn)一步改進(jìn)可采用反射技術(shù)。
客戶端測(cè)試
let total: number = 1000; ?//購買原價(jià)
let cc_1: CashContext = new CashContext("Normal"); // 原價(jià)
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
優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
1、?策略模式提供了管理相關(guān)的算法族的辦法。策略類的等級(jí)結(jié)構(gòu)定義了一個(gè)算法或行為族。恰當(dāng)使用繼承可以把公共的代碼轉(zhuǎn)移到父類里面,從而避免重復(fù)的代碼。
2、?策略模式提供了可以替換繼承關(guān)系的辦法。繼承可以處理多種算法或行為。如果不是用策略模式,那么使用算法或行為的環(huán)境類就可能會(huì)有一些子類,每一個(gè)子類提供一個(gè)不同的算法或行為。但是,這樣一來算法或行為的使用者就和算法或行為本身混在一起。決定使用哪一種算法或采取哪一種行為的邏輯就和算法或行為的邏輯混合在一起,從而不可能再獨(dú)立演化。繼承使得動(dòng)態(tài)改變算法或行為變得不可能。
3、?使用策略模式可以避免使用多重條件轉(zhuǎn)移語句。多重轉(zhuǎn)移語句不易維護(hù),它把采取哪一種算法或采取哪一種行為的邏輯與算法或行為的邏輯混合在一起,統(tǒng)統(tǒng)列在一個(gè)多重轉(zhuǎn)移語句里面,比使用繼承的辦法還要原始和落后。
?
缺點(diǎn):
1、客戶端必須知道所有的策略類,并自行決定使用哪一個(gè)策略類。這就意味著客戶端必須理解這些算法的區(qū)別,以便適時(shí)選擇恰當(dāng)?shù)乃惴?。換言之,策略模式只適用于客戶端知道所有的算法或行為的情況。
2、 策略模式造成很多的策略類,每個(gè)具體策略類都會(huì)產(chǎn)生一個(gè)新類。有時(shí)候可以通過把依賴于環(huán)境的狀態(tài)保存到客戶端里面,而將策略類設(shè)計(jì)成可共享的,這樣策略類實(shí)例可以被不同客戶端使用。換言之,可以使用享元模式來減少對(duì)象的數(shù)量。
