Typescript 裝飾者模式(Decorator)

標籤: 前端 設計模式 裝飾者模式 typescript Decorator Wrapper


如果下面的代碼你能輕易閱讀,那麼你已經熟悉裝飾者模式,可以接着學習其他的設計模式。

裝飾者模式

裝飾者模式: 裝飾模式是在不必改變原類文件和使用繼承的情況下,動態地擴展一個對象的功能。它是通過創建一個包裝對象,也就是裝飾來包裹真實的對象。

實際場景

我們購買一件白色/黑色的衣服。購買的主體是一件衣服。而白色和黑色是衣服的裝飾,就像是條紋的/碎花的。
這時我們常常把白色/黑色,條紋/碎花作爲裝飾器裝飾在衣服上。
如果需要爲類增添特性或者職責,而從該類派生子類的解決辦法並不實際的話,就應該使用裝飾者模式。

裝飾者模式的結構

  • 裝飾對象和真實對象有相同的接口。這樣客戶端對象就能以和真實對象相同的方式和裝飾對象交互。
  • 裝飾對象包含一個真實對象的引用(reference)
  • 裝飾對象接受所有來自客戶端的請求。它把這些請求轉發給真實的對象。
  • 裝飾對象可以在轉發這些請求以前或以後增加一些附加功能。這樣就確保了在運行時,不用修改給定對象的結構就可以在外部增加附加的功能。在面向對象的設計中,通常是通過繼承來實現對給定類的功能擴展。

裝飾者模式的例子

製作一件有顏色的衣服
衣服的接口

/* i-clothes.ts */
export default interface IClothes {
    setColor: (color) => any;
    setType: (type) => any;
}

一個衣服的類實現衣服的接口,一個修改顏色的類實現衣服的接口

/* clothes-class.ts */
import IClothes from './i-clothes';

export class Clothes implements IClothes {
    public color: string;
    public type: string;

    public setColor (color) {
        this.color = color;
    }

    public setType (type) {
        this.type = type;
    }
}

export class ChangeColor implements IClothes {
    public clothes: IClothes;

    constructor (clothes: IClothes) {
        // 對原對象進行'引用'
        this.clothes = clothes;
    }

    public setColor (color) {
        console.log('will be overridden')
    }

    public setType (type) {
        // 將操作轉發給原對象
        this.clothes.setType(type);
    }
}

兩個顏色的類繼承衣服的接口

/* color-class.ts */
import { ChangeColor } from './clothes-class';
import IClothes from './i-clothes';

export class WhiteClothes extends ChangeColor {
    constructor (clothes: IClothes) {
        super(clothes);
    }

    public setColor () {
        this.clothes.setColor('white');
    }

    // 在裝飾類中添加更多方法
    public whiteFun () {
        console.log('This is white function');
    }
}

export class BlackClothes extends ChangeColor {
    constructor (clothes: IClothes) {
        super(clothes);
    }

    public setColor () {
        this.clothes.setColor('black');
    }

    public blackFun () {
        console.log('This is black function')
    }
}

客戶端的實現

/* client.ts */
import { Clothes } from './clothes-class';
import { BlackClothes, WhiteClothes } from './color-class';
import IClothes from './i-clothes';

class Client {
    public getBlackClothesAndWhiteClothes () {
        const clothes: IClothes = new Clothes();
        const whiteClothes: WhiteClothes = new WhiteClothes(clothes);
        whiteClothes.setColor();
        whiteClothes.whiteFun();
        const blackClothes: BlackClothes = new BlackClothes(clothes);
        blackClothes.setColor();
        blackClothes.blackFun();
    }
}

new Client().getBlackClothesAndWhiteClothes();

當衣服是白色的時候會擁有白色衣服的特性和方法,當衣服變成黑色的時候,會擁有黑色衣服的特性和方法。

裝飾者模式的利弊

優點

  • Decorator模式與繼承關係的目的都是要擴展對象的功能,但是Decorator可以提供比繼承更多的靈活性。
  • 通過使用不同的具體裝飾類以及這些裝飾類的排列組合,設計師可以創造出很多不同行爲的組合。

缺點

  • 這種比繼承更加靈活機動的特性,也同時意味着更加多的複雜性。
  • 裝飾模式會導致設計中出現許多小類,如果過度使用,會使程序變得很複雜。
  • 裝飾模式是針對抽象組件(Component)類型編程。但是,如果你要針對具體組件編程時,就應該重新思考你的應用架構,以及裝飾者是否合適。當然也可以改變Component接口,增加新的公開的行爲,實現“半透明”的裝飾者模式。在實際項目中要做出最佳選擇。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章