設計模式:裝飾器(Decorator)模式
設計模式:裝飾器(Decorator)模式
一、前言
裝飾器模式也是一種非常重要的模式,在Java以及程序設計中占據著重要的地位。比如Java的數據流處理,我們可能看到數據流經過不同的類的包裝和包裹,最終形成了我們需要的流,比如說從二進制到字節流再到字符流,這中間其實就是經過了裝飾器的處理,在不改變原來的數據的基礎上,加入屬於自己的特征,就像是在一塊蛋糕上加上一些水果等裝飾品,這樣輸出的結果就不同了,我們將這種能產生類似於洋蔥一樣層層包裹的數據格式的設計模式成為裝飾器模式。
那麽為什麽裝飾器這樣神奇呢,幾乎可以讓我們無窮盡的包裹自身,在計算機中凡是能夠無窮盡的重復某一件事物,必然不能設定固定的數據,只能按照用戶的隨意設置來計算,那麽遞歸
二、代碼
上圖中,StringDisplay是保存原始數據的,而Border中將父類的引用組合進入自身,形成了遞歸的必然條件,之後讓子類(SideBorder和FullBorder)來使用這個引用,從而根據自身的實際情況(要怎樣裝飾)來進行包裝,將原始的數據getRowText(rowID)進行包裹,最終通過同源祖先類的show()方法來現實,這裏祖先類Display使用了面向抽象編程的模板方法,相信大家都能看出來。對比與上一個組合模式,我們可以看到上面的部分還是很相似的,但是在composite中,都實現了add()方法,通過容器來進行組織,並且使用委托機制來存儲所有的有著共同父類的元素,在顯示的時候使用了樹的深度優先遍歷。而在裝飾器模式中,我們使用的遞歸從上到下,沿著display的指向一點點的走到了底部,並且最終返回了過來。遍歷的方式有著相似之處也有著不同之處。這裏要說明的是,關於裝飾器的分析是原理上的,在實現的時候,其實在new這個過程中
Display 類:
1 package zyr.dp.decorator; 2 3 public abstract class Display { 4 5 public abstract int getColunmns(); 6 public abstract int getRows(); 7 public abstract String getTowText(int rowID); 8 public void show(){ 9 for(int i=0;i<getRows();i++){ 10 System.out.println(getTowText(i)); 11 } 12 } 13 14 }
StringDisplay類:
1 package zyr.dp.decorator; 2 3 public class StringDisplay extends Display { 4 5 String name; 6 7 public StringDisplay(String name){ 8 this.name=name; 9 } 10 11 public int getColunmns() { 12 return name.getBytes().length; 13 } 14 15 public int getRows() { 16 return 1; 17 } 18 19 public String getTowText(int rowID) { 20 if(rowID==0){ 21 return name; 22 }else{ 23 return null; 24 } 25 } 26 27 }
Border類:
1 package zyr.dp.decorator; 2 3 public abstract class Border extends Display { 4 5 protected Display display; 6 public Border(Display display){ 7 this.display=display; 8 } 9 }
SideBorder類:
1 package zyr.dp.decorator; 2 3 public class SideBorder extends Border { 4 5 String ch; 6 protected SideBorder(Display display,String ch) { 7 super(display); 8 this.ch=ch; 9 } 10 11 public int getColunmns() { 12 return display.getColunmns()+2; 13 } 14 15 public int getRows() { 16 return display.getRows(); 17 } 18 19 public String getTowText(int rowID) { 20 return ch+display.getTowText(rowID)+ch; 21 } 22 23 }
FullBorder類:
1 package zyr.dp.decorator; 2 3 public class FullBorder extends Border { 4 5 public FullBorder(Display display) { 6 super(display); 7 } 8 9 public int getColunmns() { 10 return display.getColunmns()+2; 11 } 12 13 public int getRows() { 14 return display.getRows()+2; 15 } 16 17 public String getTowText(int rowID) { 18 if(rowID==0){ 19 return "+"+makeLine("-",display.getColunmns())+"+"; 20 }else if(rowID==display.getRows()+1){ 21 return "+"+makeLine("-",display.getColunmns())+"+"; 22 }else{ 23 return "|"+display.getTowText(rowID-1)+"|"; 24 } 25 } 26 private String makeLine(String ch,int count){ 27 StringBuffer sb=new StringBuffer(); 28 for(int i=0;i<count;i++){ 29 sb.append(ch); 30 } 31 return sb.toString(); 32 } 33 34 }
Main類:
1 package zyr.dp.decorator; 2 3 public class Main { 4 5 public static void main(String[] args) { 6 7 Display d1=new StringDisplay("朱彥榮"); 8 d1.show(); 9 System.out.println("\n"); 10 Display d2=new SideBorder(d1,"*"); 11 d2.show(); 12 System.out.println("\n"); 13 Display d3=new FullBorder(d2); 14 d3.show(); 15 System.out.println("\n"); 16 Display d4=new SideBorder( 17 new FullBorder( 18 new FullBorder( 19 new SideBorder( 20 new FullBorder( 21 new StringDisplay("李山秀") 22 ), 23 "#" 24 ) 25 ) 26 ), 27 "*" 28 ); 29 d4.show(); 30 } 31 32 }
運行結果:
三、總結
可以看到裝飾模式中,保證了裝飾邊框與被裝飾物體的一致性(有共同父類),使用了模板方法,這個方法幾乎無處不在呀,同樣使用了委托(組合),通過在原始數據上面一層層的包裹,最終得到了我們想要的輸出,有著非常廣泛的用處。
設計模式:裝飾器(Decorator)模式