<大話設計模式>本教程說明及著作權聲明
國士工作室是一支專註於Android平台企業級應用開發的技術團隊,致力於做中國最棒的Android應用程式開發機構,提供最棒的Android企業級應用開發培訓服務。
企業培訓和開發合作官方連絡方式:
電話:18610086859
Email:hiheartfirst@gmail.com
QQ:1740415547
QQ群:148325348
國士工作室 有你更美好!
l 該文檔參考和使用了網路上的免費開放的圖片和內容,並以免費開放的方式發布,希望為移動互連網和智能手機時代貢獻綿薄之力!可以隨意轉載,但不得使用該文檔謀利。
l 如果對該文檔有任何疑問或者建議,請進入官方部落格
http://www.cnblogs.com/guoshiandroid/留言或者直接與國士工作室聯絡(後附連絡方式),我們會謹慎參考您的建議並根據需要對本文檔進行修改,以造福更多開發人員!
l 《大話設計模式》的最新及完整內容會在國士工作室官方部落格定期更新,請訪問國士工作室部落格
http://www.cnblogs.com/guoshiandroid/擷取更多更新內容。
組合模式 MM的生日禮物
組合模式應用情境舉例:
MM今天過生日。對GG說道“今天我過生日,你要送我一件大禮物:-O“,“嗯,好吧,去商店,你自己挑吧。”“這件T恤挺漂亮,再加上這條裙子,哎,再來一個這個包也不錯。就是它了,一套大禮。”,“能不能在包裡面再裝點什麼,算是送我一個滿的包……”,GG無語~~o(>_<)o
~~
組合模式解釋:
組合模式(Composite Pattern)是構造型的設計模式之一,是指將對象組合成樹形結構以表示“部分-整體”的階層,組合模式使得客戶對單個對象和組合對象的使用具有一致性。
英文定義為:Compose objects into tree
structures to represent part-whole hierarchies. Composite lets clients treat
individual objects and compositions of objects uniformly.
組合模式的UML圖:
組合模式所涉及的角色如下:
抽象組件角色(Component):它為組合中的對象聲明介面,也可以為共有介面實現預設行為。
樹葉組件角色(Leaf):在組合中表示分葉節點對象沒有子節點,實現抽象組件角色聲明的介面。
樹枝組件角色(Composite):在組合中表示分支節點對象,有子節點,實現抽象組件角色聲明的介面;儲存子組件。
組合模式的UML圖如下 所示:
組合模式深入分析:
將客戶代碼與複雜的對象容器結構解耦是組合模式的核心思想,解耦之後,客戶代碼將與純粹的抽象介面——而非對象容器的複內部實現結構——發生依賴關係,從而更能應對變化。
組合模式中必須提供對子物件的管理方法,不然無法完成對子物件的添加刪除等等操作,也就失去了靈活性和擴充性。但是管理方法是在Component中就聲明還是在Composite中聲明呢?一種方式是在Component裡面聲明所有的用來管理子類對象的方法,以達到Component介面的最大化。目的就是為了使客戶看來在介面層次上樹葉和分支沒有區別——透明性。但樹葉是不存在子類的,因此聲明的一些方法對於樹葉來說是不適用的。這樣也就帶來了一些安全性問題。另一種方式就是只在Composite裡面聲明所有的用來管理子類對象的方法。這樣就避免了上一種方式的安全性問題,但是由於葉子和分支有不同的介面,所以又失去了透明性。《設計模式》一書認為:在這一模式中,相對於安全性,我們比較強調透明性。對於第一種方式中葉子節點內不需要的方法可以使用空處理或者異常報告的方式來解決。
組合模式在具體實現中,可以讓父物件中的子物件反向追溯;如果父物件有頻繁的遍曆需求,可使用緩衝技巧來改善效率。
組合模式使用情境分析及代碼實現:
在上面的使用情境中,MM的生日禮物可以看做根節點,一套大禮物可以看做是樹枝構組件角色,一套大禮物中的T恤、裙子和包包是樹葉組件角色,UML圖如下所示:
建立禮物節點的抽象介面:
package com.diermeng.designPattern.Composite; import java.util.List; /* * 禮物節點的抽象 */ public interface Gift { //顯示禮物的樹枝角色或者樹葉角色的名稱 public void display(); //添加 public boolean add(Gift file); //移除 public boolean remove(Gift file); //獲得子節點 public List<Gift> getChildren(); } |
禮物的樹枝節點:
package com.diermeng.designPattern.Composite.impl; import java.util.ArrayList; import java.util.List; import com.diermeng.designPattern.Composite.Gift; /* * 禮物的樹枝節點 實現了禮物的抽象節點 */ public class GiftComposite implements Gift{ /* * 禮物樹枝節點的名稱屬性 */ private String name; /* * 禮物樹枝節點的子節點 */ private List<Gift> children; public GiftComposite(String name) { this.name = name; children = new ArrayList<Gift>(); } public void display() { System.out.println(name); } public List<Gift> getChildren() { return children; } public boolean add(Gift file) { return children.add(file); } public boolean remove(Gift file) { return children.remove(file); } } |
建立禮物節點的樹分葉節點:
package com.diermeng.designPattern.Composite.impl; import java.util.List; import com.diermeng.designPattern.Composite.Gift; public class GiftLeaf implements Gift { private String name; public GiftLeaf(String name) { this.name = name; } public void display() { System.out.println(name); } public List<Gift> getChildren() { return null; } public boolean add(Gift file) { return false; } public boolean remove(Gift file) { return false; } } |
建立一個測試用戶端:
package com.diermeng.designPattern.Composite.client; import java.util.List; import com.diermeng.designPattern.Composite.Gift; import com.diermeng.designPattern.Composite.impl.GiftComposite; import com.diermeng.designPattern.Composite.impl.GiftLeaf; public class CompositeTest { public static void main(String[] args) { //樹枝元件節點 Gift gift = new GiftComposite("大禮物"); //樹葉元件節點 Gift shirt = new GiftLeaf("T恤"); Gift skirt = new GiftLeaf("裙子"); Gift bag = new GiftLeaf("包包"); //把樹分葉節點加入到樹枝節點中 gift.add(shirt); gift.add(skirt); gift.add(bag); //調用樹的遍曆方法,來顯示整棵樹 displayTree(gift,0); } public static void displayTree(Gift gift, int deep) { for(int i = 0; i < deep; i++) { System.out.print("--"); } //顯示自身的名稱 gift.display(); //獲得子樹 List<Gift> children = gift.getChildren(); //遍曆子樹 for(Gift file : children) { if(file instanceof GiftLeaf) { for(int i = 0; i <= deep; i++) { System.out.print("--"); } file.display(); } else { displayTree(file,deep + 1); } } } } |
運行結果如下:
組合模式的優缺點分析:
優點:
使用戶端調用簡單,用戶端可以一致的使用組合結構或其中單個對象,使用者就不必關係自己處理的是單個對象還是整個組合結構,這就簡化了用戶端代碼。
更容易在組合體內加入對象組件.
用戶端不必因為加入了新的對象組件而更改代碼。
缺點:
使用組合模式雖然可以更容易的在組合體內加入新的對象組件,帶來了很大的靈活性,而且用戶端也使用者為此修改代碼,但是,如果不對新的對象組件加以合理的控制,會構成非常龐大的樹形結構,這就會導致在遍曆的時候過大的記憶體開銷。
組合模式的實際應用簡介:
組合模式適用於以下的情況:
第一:用於表示部分-整體結構
第二:希望用戶端忽略組合對象恩和單個對象,用戶端將統一的使用組合結構中的所有對象。
同時在使用組合模式的有以下要點:
組合模式採用樹形結構來實現普遍存在的對象容器,從而將一對多的關係轉化一對一的關係,使得客戶代碼可以一致地處理對象和對象容器,無需關心處理的是單個的對象,還是組合的對象容器。
將客戶代碼與複雜的對象容器結構解耦是組合模式的核心思想,解耦之後,客戶代碼將與純粹的抽象介面——而非對象容器的複內部實現結構——發生依賴關係,從而更能應對變化。
組合模式中,是將Add和Remove等和對象容器相關的方法定義在;表示抽象對象的Component類中,還是將其定義在表示對象容器的中,是一個關乎透明性和安全性的兩難問題,需要仔細權衡。建議才有透明的方式,這裡有可能違背物件導向的單一職責原則,但是對於這種特殊結構,這又是必須付出的代價。
組合模式在具體實現中,可以讓父物件中的子物件反向追溯;如果父物件有頻繁的遍曆需求,可使用緩衝技巧來改善效率。
溫馨提示:
組合模式解耦了用戶端程式和複雜元素內部結構,從而使用戶端程式可以像處理簡單元素一樣來處理複雜元素。
在整個對象樹中,如果我們經常從子物件獲得父物件,尤其是活的根節點的對象,我們可以採用緩衝技巧來改善效率。