設計模式之裝飾模式

冬天已經來臨,北方的小夥伴們是否是感受天氣一天比一天冷了呢?從秋天過渡到冬天,冷了就穿一件毛衣,若是穿上毛衣還以爲冷可能會添一件羽絨服,若是下雪天可能就須要穿上雨衣或者帶上雨傘了。在咱們生活中這些衣服以拓展的方式給了你溫暖,可是它們並非你的一部分,若是到了春天那麼這些衣服可能會一一的脫掉了。學習

在軟件開發過程當中,有事想用一些現存的類或者組件,這些類或者組件可能只是完成了一些核心功能。但在不改變其結構的狀況下,能夠動態的拓展其功能。全部這些均可以用裝飾模式來實現。this

什麼裝飾模式

裝飾模式:指的是在沒必要改變原類文件和使用繼承的狀況下,動態地擴展一個對象的功能。它是經過建立一個包裝對象,也就是裝飾來包裹真實的對象。 —— 節選自百度百科編碼

裝飾模式有兩種方式能夠實現給一個類或者一個對象添加行爲,第一種是使用繼承,使用繼承是給現有類添加功能的一種有效途徑,經過繼承一個現有類能夠使得子類在擁有自身方法的同時還擁有父類的方法。可是這種方法是靜態的,用戶不能控制增長行爲的方式和時機。第一種則是使用關聯的方法,即將一個類的對象嵌入到另外一個對象中,由另外一個對象來決定是否調用嵌入對象的行爲以便擴展本身的行爲。spa

裝飾模式優缺點

裝飾模式以對客戶透明的方式動態地給一個對象附加上更多的責任,換言之,客戶端並不會以爲對象在裝飾前和裝飾後有什麼不一樣。裝飾模式能夠在不須要建立更多子類的狀況下,將對象的功能加以擴展。設計

優勢
  1. 裝飾模式與繼承關係的目的都是擴展對象的功能,可是裝飾模式能夠提供比繼承更多的靈活性。
  2. 能夠經過一種動態的方式來擴展一個對象的功能,經過配置文件能夠在運行時選擇不一樣的裝飾器,從而實現不一樣的行爲。
  3. 經過使用不一樣的具體裝飾類以及這些裝飾類的排列組合,能夠創造出不少不一樣的行爲的組合。能夠使用多個具體裝飾類來裝飾同一個對象,獲得功能更爲強大的對象。
  4. 具體構建類與具體裝飾類能夠獨立變化,用戶能夠根據須要增長新的具體構建類和具體裝飾類,在使用其進行組合,原有代碼無需改變
缺點
  1. 是以哦那個裝飾模式進行系統設計時將產生不少小對象,這些對象的區別在於他們之間的相互鏈接的方式有所不一樣,而不是他們的類或者屬性值有所不一樣,同時還會由不少具體的裝飾類。這些裝飾類和小對象的產生將增長系統的複雜度,加大學習理解的難度。
  2. 這種比繼承更加靈活機動平的特性,也同時意味着裝飾模式比繼承更加易於出錯,排錯也是蠻困難的,對於屢次裝飾的對象,調試時尋找錯誤可能須要逐級排場,較爲繁瑣,項目複雜度偏高。

示例

裝飾模式的主要角色以下:調試

  1. 部件:聲明封裝器和被封裝的對象的公用接口
  2. 具體部件:類是被封裝對象所屬的類。它定義了基礎行爲,但裝飾類改變了這些行爲
  3. 基礎裝飾:類擁有一個指向被封裝對象的引用成員變量。該變量的類型應當被聲明尾通用部件接口這樣就能夠引用具體的部件接口,這樣他就能夠引用具體的部件和裝飾。
  4. 具體裝飾類:定義類可動態添加到部件的額外行爲。具體裝飾類會重寫裝飾基類的方法,並在調用父類方法以前或以後進行額外的行爲。
  5. 客戶端:能夠使用多層裝飾來封裝來裝飾部件,只要它能使用通用接口與全部對象交互便可。

類圖以下所示:code

image

代碼示例:component

// 抽象構件
abstract class Component {
    public abstract operate() : void;
}

// 具體構件
class ConcreteComponent extends Component {
    public operate() : void {
        console.log('do something');
    }
}

// 裝飾角色
abstract class Decorator extends Component {
    private component : Component = null;
    constructor(component : Component ) {
        super();
        this.component = component;
    }

    public operate() : void {
        this.component.operate();
    }
}

// 具體裝飾者
class ConcreteDecoratorA extends Decorator {
    constructor(component : Component) {
        super(component);
    }

    // 定義本身的修飾方法
    private methodA() : void {
        console.log('methodA修飾');
    }

    // 重寫父類方法
    public operate() : void {
        this.methodA();
        super.operate();
    }
}

class ConcreteDecoratorB extends Decorator {
    constructor(component : Component) {
        super(component);
    }

    // 定義本身的修飾方法
    private methodB() : void {
        console.log('methodB修飾');
    }

    // 重寫父類方法
    public operate() : void {
        this.methodB();
        super.operate();
    }
}

function main() {
    let component : Component = new ConcreteComponent();
    // 第一次裝飾
    component = new ConcreteDecoratorA(component);
    // 第二次裝飾
    component = new ConcreteDecoratorB(component);
    // 裝飾後運行
    component.operate();
}

main();

總結

裝飾模式來實現擴展比繼承更加靈活,它以對客戶透明的方式動態地給一個對象附加更多的責任。裝飾模式能夠在不須要創造更多子類的狀況下,將對象的功能加以擴展。對象

繼承是一種耦合度較大的靜態關係,沒法在程序運行時動態擴展。在軟件開發階段,關聯關係雖然不會比繼承關係減小編碼量,可是到了軟件維護階段,因爲關聯關係使系統具備較好的鬆耦合性,所以使得系統更加容易維護。blog

相關文章
相關標籤/搜索