《消失的設(shè)計(jì)模式》系列之策略模式

要解決的問(wèn)題

想象一下,對(duì)于某個(gè)任務(wù),我們需要支持多種解決方案。而這多種支持就是變化點(diǎn),為了封裝變換點(diǎn),我們可以采用策略模式。

定義

定義了一系列的算法,把它們分別封裝起來(lái),并且使它們可以相互替換。

此模式讓算法的變化獨(dú)立于使用算法的客戶。

面向?qū)ο蟮姆绞?/h2>

UML

strategy-uml.png

如上圖所示,

  • Strategy 接口定義了算法的行為
  • 一系列的算法 ConcreteStrategyAConcreteStrategyB 分別實(shí)現(xiàn)了該接口
  • 策略被包含在一個(gè) Context 中,擁有私有的 strategy 實(shí)例,從而執(zhí)行具體的算法行為
  • 通常 Context 中還會(huì)包含一個(gè) setStrategy 方法,從而動(dòng)態(tài)改變策略

代碼

首先我們定義一個(gè)接口 IStrategy

interface IStrategy {
  calculate(a: number, b: number): number
}

它要求實(shí)現(xiàn)一個(gè)名為 calculate 的方法,該方法接受兩個(gè) number 類型的參數(shù),最終返回一個(gè) number 類型的值。

class AddStrategy implements IStrategy {
  calculate(a: number, b: number): number {
    return a + b
  }
}

class SubtractStrategy implements IStrategy {
  calculate(a: number, b: number): number {
    return a - b
  }
}

這里我們定義了兩個(gè)具體的策略類 AddStrategySubtractStrategy,它們都實(shí)現(xiàn)了 IStrategy 接口。

最終我們來(lái)定義 Context 類:

class Context {
  private strategy: IStrategy

  constructor(strategy: IStrategy) {
    this.strategy = strategy
  }

  public setStrategy(strategy: IStrategy) {
    this.strategy = strategy
  }

  public calculate(a: number, b: number) {
    return this.strategy.calculate(a, b)
  }
}

類中包含一個(gè)私有的成員屬性 strategy,可以通過(guò)構(gòu)造函數(shù)賦值,也可以通過(guò) setStrategy 來(lái)動(dòng)態(tài)改變。最后 calculate 方法將會(huì)代理到具體的策略類上,并執(zhí)行具體的算法。

const context = new Context(new AddStrategy())
console.log(context.calculate(1, 2)) // 3
context.setStrategy(new SubtractStrategy())
console.log(context.calculate(1, 2)) // -1

context.setStrategy(new SubtractStrategy())
console.log(context.calculate(1, 2)) // -1

完整代碼

帶上函數(shù)式的思考帽

我們?cè)倩剡^(guò)頭來(lái)思考策略的定義方式:

interface IStrategy {
  calculate(a: number, b: number): number
}

這里的接口表達(dá)的意思是,期望一個(gè)類,擁有 calculate 方法,同時(shí)方法的簽名是 (number, number) -> number。

其實(shí)真正想要的,只是里面的這個(gè)方法而已,我們大可不必將其放在類里面??梢园呀涌谛薷某扇缦碌臉幼樱?/p>

interface IStrategy {
  (a: number, b: number): number
}

這里 IStrategy 表達(dá)的意思是,一個(gè)函數(shù),類型為 (number, number) -> number。如有有些不好理解的話,我們可以將其改為 type:

type IStrategy = (a: number, b: number) => number

那么相應(yīng)的策略可以修改為:

const AddStrategy: IStrategy = (a, b) => a + b
const SubtractStrategy: IStrategy = (a, b) => a - b

這時(shí),Context 就變成了:

class Context {
  private strategy: IStrategy

  constructor(strategy: IStrategy) {
    this.strategy = strategy
  }

  public setStrategy(strategy: IStrategy) {
    this.strategy = strategy
  }

  public calculate(a: number, b: number) {
    return this.strategy(a, b)
  }
}

const context = new Context(AddStrategy)
console.log(context.calculate(1, 2)) // 3
context.setStrategy(SubtractStrategy)
console.log(context.calculate(1, 2)) // -1

context.setStrategy(SubtractStrategy)
console.log(context.calculate(1, 2)) // -1

只是傳入一個(gè)函數(shù)而已!去掉了類的層層包裹,一個(gè)函數(shù)就可以清晰明了地解決問(wèn)題。

由于場(chǎng)景的設(shè)定,這里我們就不去將 Context 函數(shù)式化了。
完整代碼

總結(jié)

策略模式,其目的是使不同算法族變得可控。其方法是將符合統(tǒng)一接口的不同行為的類的實(shí)例注入進(jìn)入。但是如果能使用函數(shù)式的方式,其實(shí)傳一個(gè)函數(shù)參數(shù),就可以了。

參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容