TypeScript 設計模式之模板方法

1、簡介

模板方法模式是一種只需使用繼承就能夠實現的很是簡單的模式。模板方法模式由兩部分結構組成,第一部分是抽象父類,第二部分是具體的實現子類。一般在抽象父類中封裝了子類的算法框架,也包括實現一些公共方法以及封裝子類中全部方法的執行順序。子類經過繼承這個抽象類,也繼承了整個算法結構,而且能夠選擇重寫父類的方法。算法

2、優缺點

優勢

  • 在父類中形式化地定義一個算法,而由它的子類來實現細節的處理,在子類實現詳細的處理算法時並不會改變算法中步驟的執行次序。
  • 模板方法模式是一種代碼複用技術,它在類庫設計中尤其重要,它提取了類庫中的公共行爲,將公共行爲放在父類中,而經過子類來實現不一樣的行爲,它鼓勵咱們恰當使用繼承來實現代碼複用。
  • 可實現一種反向控制結構,經過子類覆蓋父類的鉤子方法來決定某一特定步驟是否須要執行。
  • 在模板方法模式中能夠經過子類來覆蓋父類的基本方法,不一樣的子類能夠提供基本方法的不一樣實現,更換和增長新的子類很方便,符合單一職責原則和開閉原則。

缺點

  • 須要爲每個基本方法的不一樣實現提供一個子類,若是父類中可變的基本方法太多,將會致使類的個數增長,系統更加龐大,設計也更加抽象。此時,能夠結合橋接模式來進行設計。

3、應用場景

  • 一個類不知道它所須要的對象的類:在工廠方法模式中,客戶端不須要知道具體產品類的類名,只須要知道所對應的工廠便可,具體的產品對象由具體工廠類建立;客戶端須要知道建立具體產品的工廠類。
  • 一個類經過其子類來指定建立哪一個對象:在工廠方法模式中,對於抽象工廠類只須要提供一個建立產品的接口,而由其子類來肯定具體要建立的對象,利用面向對象的多態性和里氏代換原則,在程序運行時,子類對象將覆蓋父類對象,從而使得系統更容易擴展。

4、模式結構

模板方法模式包含如下角色:typescript

  • AbstractClass(抽象類):在抽象類中定義了一系列基本操做 (PrimitiveOperations),這些基本操做能夠是具體的,也能夠是抽象的,每個基本操做對應算法的一個步驟,在其子類中能夠重定義或實現這些步驟。同時,在抽象類中實現了一個模板方法,用於定義一個算法的框架,模板方法不只能夠調用在抽象類中實現的基本方法,也能夠調用在抽象類的子類中實現的基本方法,還能夠調用其餘對象中的方法。
  • ConcreteClass(具體子類):它是抽象類的子類,用於實如今父類中聲明的抽象基本操做以完成子類特定算法的步驟,也能夠覆蓋在父類中已經實現的具體基本操做。

template-method-uml.jpg

5、實戰

具體實現

定義 AbstractClass 抽象類segmentfault

class AbstractClass {
    public method1(): void {
        throw new Error("Abstract Method");
    }

    public method2(): void {
        throw new Error("Abstract Method");
    }

    public method3(): void {
        throw new Error("Abstract Method");
    }

    public templateMethod(): void {
        console.log("templateMethod is being called");
        this.method1();
        this.method2();
        this.method3();
    }
}

定義 ConcreteClass 類設計模式

class ConcreteClass extends AbstractClass {
    public method1(): void {
        console.log("method1 of ConcreteClass");
    }

    public method2(): void {
        console.log("method2 of ConcreteClass");
    }

    public method3(): void {
        console.log("method3 of ConcreteClass");
    }
}

使用示例

function show(): void {
    const cc: ConcreteClass = new ConcreteClass();
    cc.templateMethod();
}

以上代碼成功運行後會輸出如下結果:框架

templateMethod is being called
method1 of ConcreteClass
method2 of ConcreteClass
method3 of ConcreteClass

下面爲了讓小夥伴們能更好地理解模板方法設計模式,咱們來以 「泡咖啡與泡茶」 這個經典的例子來深刻介紹模板方法。this

首先,咱們先來泡一杯咖啡,泡咖啡的步驟一般以下:spa

  1. 把水煮沸
  2. 用沸水沖泡咖啡
  3. 把咖啡倒進杯子
  4. 加糖和牛奶

接下來,開始準備咱們的茶,泡茶的步驟跟泡咖啡的步驟相似:設計

  1. 把水煮沸
  2. 用沸水浸泡茶葉
  3. 把茶水倒進杯子
  4. 加檸檬

根據上面泡咖啡和泡茶的步驟,咱們能夠整理出如下表格:code

泡咖啡步驟 泡茶步驟
把水煮沸 把水煮沸
用沸水沖泡咖啡 用沸水浸泡茶葉
把咖啡倒進杯子 把茶水倒進杯子
加糖和牛奶 加檸檬

咱們能夠發現泡咖啡和泡茶主要有如下不一樣點:對象

  • 原料不一樣。一個是咖啡,一個是茶,但咱們能夠把它們都抽象爲 「飲料」。
  • 泡的方式不一樣。咖啡是沖泡,而茶葉是浸泡,咱們能夠把它們都抽象爲 「泡」。
  • 加入的調料不一樣。一個是糖和牛奶,一個是檸檬,但咱們能夠把它們都抽象爲 「調料」。

通過抽象以後,不論是泡咖啡仍是泡茶,咱們都能整理爲下面四步:

  1. 把水煮沸
  2. 用沸水沖泡飲料
  3. 把飲料倒進杯子
  4. 加調料

因此,不論是沖泡仍是浸泡,咱們都能給它一個新的方法名稱,好比說 brew()。同理,不論是加糖和牛奶,仍是加檸檬,咱們均可以稱之爲 addCondiments()

如今咱們能夠建立一個抽象父類來表示泡一杯飲料的整個過程。不管是咖啡(Coffee),仍是茶(Tea),都被咱們用飲料(Beverage)來表示,最後咱們來看一下具體實現。

coffee-and-tea.jpg

建立 Beverage 抽象類

abstract class Beverage {
    boilWater() {
        console.log("把水煮沸");
    }

    abstract brew(): void;
    abstract pourInCup(): void;
    abstract addCondiments(): void;

    // 模板方法
    makeBeverage() {
        this.boilWater();
        this.brew();
        this.pourInCup();
        this.addCondiments();
    }
}

建立 Coffee 類

class Coffee extends Beverage {
    brew(): void {
        console.log("用沸水沖泡咖啡");
    }
    pourInCup(): void {
        console.log("把咖啡倒進杯子");
    }
    addCondiments(): void {
        console.log("加糖和牛奶");
    }
}

建立 Tea 類

class Tea extends Beverage {
    brew(): void {
        console.log("用沸水浸泡茶葉");
    }
    pourInCup(): void {
        console.log("把茶倒進杯子");
    }
    addCondiments(): void {
        console.log("加檸檬");
    }
}

使用示例

function show(): void {
    const coffee: Coffee = new Coffee();
    const tea: Tea = new Tea();
    coffee.makeBeverage();
    tea.makeBeverage();
}

以上代碼成功運行後會輸出如下結果:

把水煮沸
用沸水沖泡咖啡
把咖啡倒進杯子
加糖和牛奶
把水煮沸
用沸水浸泡茶葉
把茶倒進杯子
加檸檬

6、總結

在模板方法設計模式中,一個抽象類公開定義了執行它的方法的方式/模板。它的子類能夠按須要重寫方法實現,但調用將以抽象類中定義的方式進行。模板方法定義一個操做中的算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類能夠不改變一個算法的結構便可重定義該算法的某些特定步驟。

本人的全棧修仙之路訂閱號,會按期分享 Angular、TypeScript、Node.js/Java 、Spring 相關文章,歡迎感興趣的小夥伴訂閱哈!

full-stack-logo

相關文章
相關標籤/搜索