重新看組合/合成(Composite)模式,發現它并不像自己想象的那么簡單,單純從整體和部分關系的角度去理解還是不夠的,并且還有一些通俗的模式講解類的書,由于其舉的例子太過“通俗”,以致讓人理解產生偏差,不過設計模式本身就是一種程序設計思想,不同的人當然會產生具有偏差性質的理解。
GOF對組合模式的定義是:將對象組合成樹形結構以表示“部分 -整體”的層次結構。 Composite使得用戶對單個對象和組合對象的使用具有一致性 。這里,“用戶對單個對象和組合對象的使用具有一致性”,這是Composite模式產生的效果。從表示形式來看,Composite表示的是“部分-整體”的關系,但是,往往忽略了效果。下圖是Composite模式的結構圖:
Composite模式的對象結果如下:
Composite類提供對Leaf類對象的管理方法,如Add(),Remove(),GetChild()方法,這些方法的定義可以有兩種方法:一個是放在Component的頂層父類中,這樣所有的子類(包括Leaf類)都會集成該方法,但Leaf類可以選擇不實現這些方法;另外一個是將對Leaf對象操作的方法放到Composite類中,并不是放到Component類中。現在以GOF所著書中所給的例子為例,寫出組合模式的代碼,類圖結構如下:
代碼如下:


1 abstract class Graphic{ 2 3 public void Draw(){} 4 public void Add(Graphic g){} 5 public void Remove(Graphic g){} 6 public Graphic GetChild(int index){return null;} 7 } 8 class Line extends Graphic{ 9 public void Draw(){ 10 System.out.println("Draw a Line"); 11 } 12 } 13 class Rectange extends Graphic{ 14 public void Draw(){ 15 System.out.println("Draw a Rectange"); 16 } 17 } 18 class Text extends Graphic{ 19 public void Draw(){ 20 System.out.println("Draw a Text"); 21 } 22 } 23 class Picture extends Graphic{ 24 private Vector<Graphic> vec=new Vector<Graphic>(); 25 public void Draw(){ 26 for(Graphic g : vec){ 27 g.Draw(); 28 } 29 } 30 public void Add(Graphic g){ 31 vec.add(g); 32 } 33 public void Remove(Graphic g){ 34 try{ 35 vec.remove(g); 36 }catch(Exception e){ 37 38 } 39 } 40 public Graphic GetChild(int index){ 41 return vec.get(index); 42 } 43 } 44 public class Test{ 45 public static void main(String[] args){ 46 Picture p=new Picture(); 47 p.Add(new Text()); 48 p.Add(new Rectange()); 49 p.Add(new Line()); 50 p.Draw(); 51 } 52 }
適用Composite模式的情況:
1、想要表示對象的部分-整體層次結構
2、希望用戶忽略組合對象與單個對象的不同,用戶將統一地使用組合結構中的所有對象。
第一句話很好理解,第二句話該怎么理解呢?我的理解是,如果有一個方法Visist(Component con){con.Draw();}實現一個動作,這時候它并不需要知道是處理一個葉子結點對象還是一個組合對象,對于傳進來的葉子結點對象,可以直接處理請求,如果是一個Composite,則將請求發給它的子部件,并且在轉發請求之前/后還可以執行一些輔助操作。有人舉過一個例子:文件和文件夾,該實現可以用組合模式,文件是Leaf,文件夾是Composite,我們可以單建文件對象,也可創建一個具有目錄結構的文件夾對象,文件夾下面可以放文件對象,也可以放文件夾對象。
為了提高系統的可復用性,有一些設計原則,其中有一條“組合/聚合復用原則”,就是優先使用“組合/聚合”,而非繼承,這里說的組合是對象組合,也就是一個對象在運行時期動態獲得其他對象的引用,從而達到不用繼承而能擴展功能的效果;顯然,對象組合的使用范圍更大,和這里的組合模式不是同一個概念,前者畢竟是一個“設計原則”,而后者則是一個成型的“模式”,原則的使用范圍當然更廣了。
通過今天的總結,對組合模式又有了進一步的認識,感謝GOF、《Java與模式》、《Thinking in Patterns》。
?