裝飾模式:
- 目的
動態地將額外的責任附加到對象上。裝飾器提供了一個靈活的子類擴展功能的替代方法。
2.要解決的問題
子類化是在編譯時靜態擴展類功能(向類添加職責)的標準方法。實例化子類後,該功能將在其生命週期綁定到該實例,並且無法在運行時進行更改。
如果我們想在運行時擴展對象的功能,而不是在編譯時擴展類的功能,則可以避免這種方法。
3.解決方案
定義單獨的Decorator對象:
定義一個類(Decorator),該類維護對Component對象的引用,並將請求轉發到該組件
定義Decorator1實現額外功能的子類,以便在請求轉發之前或之後執行
此模式的關鍵思想是遍歷Decorator“裝飾器”(已添加的)對象(向其添加職責)的單獨對象。裝飾器Component透明地實現該接口,以便它可以充當要裝飾的組件的透明外殼。“客戶端通常無法告訴他們是在處理組件還是其附件”。
因爲裝飾器是裝飾組件的透明外殼,所以它們可以遞歸嵌套以增加職責的開放性。更改裝飾器的順序允許添加職責的任意組合。
4.動機
在編譯時擴展功能:
子類執行其他職責,實例化子類後,職責將在實例的生命週期內綁定到實例,並且無法在運行時更改。
子類的爆炸式增長:通過子類擴展功能需要爲每個新功能和每個功能組合創建一個新的子類,支持大量功能及其組合將產生大量子類。
5.適用性
運行時擴展功能:
- 如何動態地將職責添加到對象(或從對象撤回)
- 如何在運行時擴展對象的功能
- 如何定義在運行時擴展的簡單類
- 而不是在複雜類中實現所有可預見的功能
子類的靈活替代:
如何爲子類提供靈活的替代方案,以便編譯時擴展類的功能
重構問題:
如何重構包含連線擴展的類。
6.結構
Component(抽象構件):它是具體構件和抽象裝飾類的共同父類,聲明瞭在具體構件中實現的業務方法,它的引入可以使客戶端以一致的方式處理未被裝飾的對象以及裝飾之後的對象,實現客戶端的透明操作。
ConcreteComponent(具體構件):它是抽象構件類的子類,用於定義具體的構件對象,實現了在抽象構件中聲明的方法,裝飾器可以給它增加額外的職責(方法)。
Decorator(抽象裝飾類):它也是抽象構件類的子類,用於給具體構件增加職責,但是具體職責在其子類中實現。它維護一個指向抽象構件對象的引用,通過該引用可以調用裝飾之前構件對象的方法,並通過其子類擴展該方法,以達到裝飾的目的。
ConcreteDecorator(具體裝飾類):它是抽象裝飾類的子類,負責向構件添加新的職責。每一個具體裝飾類都定義了一些新的行爲,它可以調用在抽象裝飾類中定義的方法,並可以增加新的方法用以擴充對象的行爲。
7.協作
8.優缺點
主要優點
裝飾模式的主要優點如下:
(1) 對於擴展一個對象的功能,裝飾模式比繼承更加靈活性,不會導致類的個數急劇增加。
(2) 可以通過一種動態的方式來擴展一個對象的功能,通過配置文件可以在運行時選擇不同的具體裝飾類,從而實現不同的行爲。
(3) 可以對一個對象進行多次裝飾,通過使用不同的具體裝飾類以及這些裝飾類的排列組合,可以創造出很多不同行爲的組合,得到功能更爲強大的對象。
(4) 具體構件類與具體裝飾類可以獨立變化,用戶可以根據需要增加新的具體構件類和具體裝飾類,原有類庫代碼無須改變,符合“開閉原則”。
主要缺點
裝飾模式的主要缺點如下:
(1) 使用裝飾模式進行系統設計時將產生很多小對象,這些對象的區別在於它們之間相互連接的方式有所不同,而不是它們的類或者屬性值有所不同,大量小對象的產生勢必會佔用更多的系統資源,在一定程序上影響程序的性能。
(2) 裝飾模式提供了一種比繼承更加靈活機動的解決方案,但同時也意味着比繼承更加易於出錯,排錯也很困難,對於多次裝飾的對象,調試時尋找錯誤可能需要逐級排查,較爲繁瑣。
9.實施
接口一致性:
裝飾器的關鍵
- 維護對裝飾對象的引用
- 通過將所有請求轉發給裝飾對象來透明地實現裝飾對象的接口。被稱爲透明外殼,客戶端通常不知道他們是在處理組件還是它的外殼
10.代碼:
package decorator;
public interface Component {
public String opreation();
}
package decorator;
public class Component1 implements Component{
@Override
public String opreation() {
// TODO Auto-generated method stub
return "Hello World from Component1 !";
}
}
package decorator;
public abstract class Decorator implements Component {
private Component component;
public Decorator(Component c) {
component=c;
}
public String opreation() {
return component.opreation();
}
}
package decorator;
public class Decorator1 extends Decorator{
public Decorator1(Component c) {
super(c);
// TODO Auto-generated constructor stub
}
public String opreation() {
return this.addMethod1()+super.opreation()+this.addMethod1();
}
public String addMethod1() {
return " *** ";
}
}
package decorator;
public class Decorator2 extends Decorator{
public Decorator2(Component c) {
super(c);
// TODO Auto-generated constructor stub
}
public String opreation() {
return this.addMethod2()+super.opreation()+this.addMethod2();
}
public String addMethod2() {
return " === ";
}
}
package decorator;
public class Client {
public static void main(String[] args) {
Component component=new Component1();
System.out.println("(1) "+component.opreation());
component=new Decorator1(new Decorator2(component));
System.out.println("(2) "+component.opreation());
}
}
11.結果: