定義 在不改變原有對象的基礎之上,將功能附加到對象上 適用場景 詳解 在看到定義的時候,可能很多人會想,這不就是繼承嗎?的確很像,不過是比繼承更加有彈性的替代方案。就像原型模式和new之間的關係一樣,有區別,但是區別又不是特別大。裝飾者一個很重要的詞就是動態,他可以靈活的選擇要這個功能還是不要。在裝 ...
定義
在不改變原有對象的基礎之上,將功能附加到對象上
適用場景
- 擴展一個類的功能
- 動態的給對象增加功能,當功能不需要的時候能夠動態刪除
詳解
在看到定義的時候,可能很多人會想,這不就是繼承嗎?的確很像,不過是比繼承更加有彈性的替代方案。就像原型模式和new之間的關係一樣,有區別,但是區別又不是特別大。裝飾者一個很重要的詞就是動態,他可以靈活的選擇要這個功能還是不要。在裝飾者中要有四個角色:抽象的實體類,具體的實體類,抽象的裝飾者,具體的裝飾者。下麵畫一個大致的UML圖
實體類創建之後,如果想擴展實體類那麼一般的想法是繼承,當然繼承也是其中方法之一。上面由UML圖就可以看出,在裝飾者模式下,我們可以通過裝飾類下的擴展功能實現對抽象實體類的包裝。當我們需要擴展功能就多加一個擴展功能,不需要擴展功能就不用添加,是一個很動態的擴展方式。下麵具體看代碼解析。
抽象實體類
public abstract class abstractCake { protected abstract String getCake(); protected abstract int cost(); }
實體類
public class cake extends abstractCake{ @Override protected String getCake() { return "蛋糕"; } @Override protected int cost() { return 100; } }
抽象裝飾類(可以抽象也可以不抽象)
public class AbstractDecorator extends abstractCake { private abstractCake abstractcake; public AbstractDecorator(abstractCake abstractcake) { this.abstractcake = abstractcake; } @Override protected String getCake() { return this.abstractcake.getCake(); } @Override protected int cost() { return this.abstractcake.cost(); } }
擴展功能1
public class FruitDecorator extends AbstractDecorator { public FruitDecorator(abstractCake abstractcake) { super(abstractcake); } @Override protected String getCake() { return super.getCake()+" 加一層水果"; } @Override protected int cost() { return super.cost()+20; } }
擴展功能2
public class SugerDecorator extends AbstractDecorator{ public SugerDecorator(abstractCake abstractcake) { super(abstractcake); } @Override protected String getCake() { return super.getCake()+" 多加糖"; } @Override protected int cost() { return super.cost()+10; } }
測試類
public class Test { public static void main(String[] args) { abstractCake ac=new cake(); ac=new FruitDecorator(ac); ac=new SugerDecorator(ac); System.out.println(ac.getCake()); } }
結果
具體的記憶體圖
可以很清楚的看見ac這個抽象類下麵一層層包著實體類,解析的時候每一層的包裝類的getCake()方法都會送回給抽象實體類,而我的getCake()方法實現的是字元串增加。後面如果我還需要一層水果,那麼我就多裝飾一次。如果用繼承實現,那麼我要兩層水果,不要糖,那麼我就還需要再定義一個實現兩層水果的子類,而裝飾者模式就只需要修改客戶端的ac類實現就行。在JDK中裝飾者模式用的最出名的莫過於IO流了,以InputStream為例子。下麵是UML圖
這就是典型的裝飾者。平常我們只需要FileInputStream來讀取文件,當我們有一些特殊功能需要,如:BufferedInputStream(完成了緩存功能,使讀取文件速度大大提升)和DataInputStream(把byte轉換成Java基本數據類型)我們就可以裝飾一下InputStream,即靈活又方便。這樣使得我們對FileInputStream流的處理更能達到我們想要的預期。當你理解了裝飾者模式,我推薦你看這篇博客。這樣你就能很好的理解IO流的操作。
總結
裝飾者模式是一個比繼承更加靈活的擴展方式,要記住裝飾者模式必不可少的4個類:抽象的實體類,具體的實體類,抽象的裝飾者,具體的裝飾者。再結合上面推薦的博客,我相信你不但能理解裝飾者,還能更加清晰的理解JDK中的IO流