23種設計模式之裝飾者模式

一、定義

在沒必要改變原類文件和使用繼承的狀況下,動態地擴展一個對象的功能。它是經過建立一個包裝對象,也就是裝飾者來包裹真實的對象。因此裝飾者能夠動態地給一個對象添加一個額外的職責。就增長功能來講,裝飾者模式相比生成子類更加靈活。編程

二、模式結構

裝飾者模式由四部分組成:bash

  • Component(抽象構件):它是具體構件和抽象裝飾類的共同父類,聲明瞭在具體構件中實現的業務方法,它的引入可使客戶端以一致的方式處理未被裝飾的對象以及裝飾以後的對象,實現客戶端的透明操做。
  • ConcreteComponent(具體構件):它是抽象構件類的子類,用於定義具體的構件對象,實現了在抽象構件中聲明的方法,裝飾者能夠給它增長額外的職責(方法)。
  • Decorator(抽象裝飾類):它也是抽象構件類的子類,用於給具體構件增長職責,可是具體職責在其子類中實現。它維護一個指向抽象構件對象的引用,經過該引用能夠調用裝飾以前構件對象的方法,並經過其子類擴展該方法,以達到裝飾的目的。
  • ConcreteDecorator(具體裝飾類):它是抽象裝飾類的子類,負責向構件添加新的職責。每個具體裝飾類都定義了一些新的行爲,它能夠調用在抽象裝飾類中定義的方法,並能夠增長新的方法用以擴充對象的行爲。

三、實例

3.1 Coffee抽象類(抽象構件)架構

public abstract class Coffee {
    public String description;
    
    public String getDescription() {
        return description;
    }
    
    public void serDescription(String description) {
        this.description = description;
    }
    
    public abstract double cost();
}
複製代碼

3.2 Coffee類(具體構件)ide

public class Mocha extends Coffee {
    
    public Mocha() {
        description = "Mocha";
    }
    
    @Override
    public double cost() {
        return 15.90;
    }
}
複製代碼
public class Espresso extends Coffee {
    
    public Espresso() {
        description = "Espresso";
    }
    
    @Override
    public double cost() {
        return 12.50;
    }
}
複製代碼

3.3 調料CondimentDecorator抽象類(抽象裝飾類)ui

public abstract class CondimentDecorator extends Coffee {
    
    @Override
    public abstract String getDescription();
}
複製代碼

3.4 調料類(具體裝飾類)this

public class Milk extends CondimentDecorator {
    
    private Coffee coffee;
    
    public Milk(Coffee coffee) {
        this.coffee = coffee;
    }
    
    @Override
    public String getDescription() {
        return coffee.getDescription() + ", Mike";
    }
    
    @Override
    public double cost() {
        return coffee.cost() + 2.0;
    }
}
複製代碼
public class Sugar extends CondimentDecorator {
    
    private Coffee coffee;
    
    public Sugar(Coffee coffee) {
        this.coffee = coffee;
    }
    
    @Override
    public String getDescription() {
        return coffee.getDescription() + ", Sugar";
    }
    
    @Override
    public double cost() {
        return coffee.cost() + 1.0;
    }
}
複製代碼

3.5 客戶端調用spa

public class Client {
    
    public static void main(String arg[]) {
        
        Coffee mocha = new Mocha();
        mocha = new Sugar(mocha);
        mocha = new Sugar(mocha);
        System.out.println(mocha.getDescription() + "$" + mocha.cost());
        
        Coffee espresso = new Espresso();
        espresso = new Milk(espresso);
        espresso = new Sugar(espresso);
        System.out.println(espresso.getDescription() + "$" + espresso.cost());
    }
}
複製代碼

四、適用場景

  • 須要擴展一個類的功能,或給一個類添加附加職責。
  • 須要動態的給一個對象添加功能,這些功能能夠在動態的撤銷。
  • 須要增長由一些基本功能的排列組合而產生的很是大量的功能,從而使繼承關係變得不現實。
  • 當不能採用生成子類的方法進行擴充時。一種狀況是,能夠由大量獨立的擴展,爲支持每一種組合將產生大量的子類,使得子類數目呈爆炸性增加。另外一種狀況多是由於類定義被隱藏,或類定義不能用於生成子類。

五、在Java IO流中的應用

六、優缺點

6.1 優勢
  • 對於擴展一個對象的功能,裝飾模式比繼承更加靈活,不會致使類的個數急劇增長。
  • 經過使用不一樣的具體裝飾類以及這些裝飾類的排列組合,能夠創造出不少不一樣行爲的組合。
  • 被裝飾者與裝飾者解耦,被裝飾者能夠不知道裝飾者的存在,同時新增功能時原有代碼也無需改變,符合「開閉原則」。
6.2 缺點
  • 裝飾模式會致使設計中出現許多小類,若是過分使用,會使程序變得很複雜。
  • 裝飾模式比繼承更加靈活機動的特性,同時也意味着比繼承更加易於出錯,拍錯也很困難,對於屢次裝飾的對象,調試時尋找錯誤可能須要逐級排查,較爲繁瑣。
  • 裝飾模式是針對抽象組件(Component)類型編程。可是,若是你要針對具體組件編程時,就應該從新思考你的應用架構,已經裝飾者是否合適。

七、透明裝飾模式和半透明裝飾模式

7.1 透明裝飾模式

在透明裝飾模式中,要求客戶端徹底針對抽象編程,裝飾模式的透明性要求客戶端程序不該該將對象聲明爲具體構件類型或具體裝飾類型,而應該所有聲明爲抽象構件抽象。設計

7.2 半透明裝飾模式

透明裝飾模式的設計難度較大,並且有時咱們須要單獨調用新增的業務方法。爲了可以調用新增方法,咱們不得不用具體裝飾類型來定義裝飾以後的對象,而具體構件類型仍是可使用抽象構件類型來定義,這種裝飾模式即爲半透明裝飾模式。調試

半透明裝飾模式能夠給系統帶來更多的靈活性,設計至關簡單,使用起來也很是方便;可是其最大的缺點在於不能實現對同一個對象的屢次裝飾,並且客戶端須要有區別地對待裝飾以前的對象和裝飾以後的對象。code

特別聲明:一、如若文中有錯之處,歡迎大神指出。 二、文章是參考網上一些大神的文章,本身整理出來的,如如有侵權,可聯繫我刪除。

相關文章
相關標籤/搜索