1、前言java
裝飾器模式也是一種很是重要的模式,在java以及程序設計中佔據着重要的地位。好比java的數據流處理,咱們可能看到數據量通過不一樣的類的包裝和包裹,最終造成了咱們須要的流,好比說從二進制到字節流再到字符流,這中間其實就是通過了裝飾器的處理,在不改變原來數據的基礎上,加入屬於本身的特徵,就像屎在一塊蛋糕上加上一些水果等裝飾品,這樣輸出的結果就不一樣了,咱們將這種產生相似於洋蔥同樣層層包裹的數據格式的設計模式稱爲裝飾器模式。apache
那麼爲何裝飾器模式這麼神奇呢,幾乎可讓咱們無窮盡的包裹自身,在計算機中凡是可以無窮盡的重複某一件事情,必然不能設定固定的數據,只能按照用戶的隨意設置來計算,那麼遞歸的魅力就在此彰顯出來了,經過遞歸能夠實現這一點,那麼如何遞歸呢,咱們想到一層套一層的數據結構,就必須在「自身」中包含「自身」;前一個「自身」能夠是咱們的子類,由於子類有着父類的全部特色,後一個「自身」就是具備抽象資格的「自身」,正是由於足夠抽象使得任何繼承與這個抽象類的類都能經過里氏代換原則轉換到這個抽象類。實現了遞歸,咱們只須要中止條件就能夠了,中止條件就是用戶在main中對元數據包裹的層數,加入新的內容,最終使用最頂層的輸出方法將這個結果呈現給咱們。一樣的咱們還能夠反着看,當遞歸開始的時候,在最頂層等待下一層的數據,而後使用頂層的方式來封裝,而下一層被啓動執行到關鍵步驟時會等待下下一層的數據返回給自身,而後是用本身的方式來封裝,就這樣一直等待下去,直到最底層的數據(原本就有)獲得以後,而後一步步的返回過來,在相應的層次進行相應的封裝,最後獲得了最終的數據。這就是裝飾器模式,全部的類其實最終都是同源(一致性)的,有最終的祖先,以下圖所示。編程
2、代碼設計模式
上圖中,StringDisplay是保存原始數據的,而Border中將父類的引用組合進入自身,造成了遞歸的必然條件,以後讓子類來使用這個引用,從而根據自身的實際狀況來進行包裝,將原始的數據getRowText(rowID)進行包裹,最終經過同源祖先類的show()方法來實現,這裏祖先類display使用了面向抽象編程的模板方法。對比組合模式,咱們能夠看到上面的部分仍是很類似的,可是在composite中,都實現了add()方法,經過容器來進行組織,而且使用委託機制來存儲全部的有着共同父類的元素,在顯示的時候使用了樹的深度優先遍歷。而在裝飾器模式中,咱們使用的遞歸從上到下,沿着display的指向一點點的走到了底部,而且最終返回了過來。遍歷的方式有着類似之處也有着不一樣之處。這裏要說明的是,建議你們在show的地方打個斷點,而後跟蹤進去,一點點的看看咱們的程序究竟是怎麼組織起來的,只有這樣咱們才能理解遞歸的含義,對裝飾器有一個更深層次的認識。數據結構
package designMode.decorator; public abstract class Display { public abstract int getColumns(); public abstract int getRows(); public abstract String getRowText(int rowID); public void show(){ for (int i = 0; i < getRows(); i++) { System.out.println(getRowText(i)); } } }
package designMode.decorator; public class StringDisplay extends Display { String name; public StringDisplay(String name) { this.name = name; } @Override public int getColumns() { return name.getBytes().length; } @Override public int getRows() { return 1; } @Override public String getRowText(int rowID) { if(rowID==0){ return name; }else { return null; } } }
package designMode.decorator; public abstract class Border extends Display { protected Display display; public Border(Display display) { this.display = display; } }
package designMode.decorator; public class SideBorder extends Border { String ch; protected SideBorder(Display display,String ch) { super(display); this.ch = ch; } @Override public int getColumns() { return display.getColumns()+2; } @Override public int getRows() { return display.getRows(); } @Override public String getRowText(int rowID) { return ch + display.getRowText(rowID)+ch; } }
package designMode.decorator; public class FullBorder extends Border { public FullBorder(Display display) { super(display); } @Override public int getColumns() { return display.getColumns()+2; } @Override public int getRows() { return display.getRows()+2; } @Override public String getRowText(int rowID) { if (rowID==0){ return "+"+makeLine("-",display.getColumns())+"+"; }else if(rowID==display.getRows()+1){ return "+"+makeLine("-",display.getColumns())+"+"; }else { return "|"+display.getRowText(rowID-1)+"|"; } } private String makeLine(String ch,int count){ StringBuffer sb = new StringBuffer(); for (int i = 0; i < count; i++) { sb.append(ch); } return sb.toString(); } }
package designMode.decorator; import com.sun.deploy.resources.Deployment_sv; import com.sun.org.apache.bcel.internal.generic.NEW; public class Main { public static void main(String[] args) { Display d1 = new StringDisplay("江疏影"); d1.show(); Display d2 = new SideBorder(d1,"*"); d2.show(); System.out.println("\n"); Display d3 = new FullBorder(d2); d3.show(); System.out.println("\n"); Display d4=new SideBorder(new FullBorder( new FullBorder( new SideBorder( new FullBorder( new StringDisplay("素小暖") ), "#") ) ), "*" ); d4.show(); } }
3、總結app
繼承保證了父類和子類的一致性(有共同的方法),委託保證了使用委託的類和被委託對象的一致性。正如Border和Display有着一些相同的方法名稱,以及一些委託處理方法。能夠看到裝飾模式中,保證了裝飾邊框與被裝飾物體的一致性(有共同父類),使用了模板方法,這個方法幾乎無處不在呀,一樣使用了委託(組合),經過在原始數據上面一層層的包裹,最終獲得了咱們想要的輸出,有着很是普遍的用處。ide
淺談設計模式<最通俗易懂的講解>this