[Toc]java
樹形結構在軟件中隨處可見,例如操做系統中的目錄結構、應用軟件中的菜單、辦公系統中的公司組織結構等。git
組合模式經過一種巧妙的設計方案使得用戶能夠一致性地處理整個樹形結構或者樹形結構的一部分,也能夠一致性地處理樹形結構中的葉子節點(不包含子節點的節點)和容器節點(包含子節點的節點)。編程
組合模式(Composite Pattern):組合多個對象造成樹形結構以表示具備「總體—部分」關係的層次結構。組合模式對單個對象(即葉子對象)和組合對象(即容器對象)的使用具備一致性,組合模式又能夠稱爲「總體—部分」(Part-Whole)模式,它是一種對象結構型模式。設計模式
在組合模式中引入了抽象構件類Component,它是全部容器類和葉子類的公共父類,客戶端針對Component進行編程。組合模式結構如圖所示:安全
代碼實現了一個公司的組織架構,包括各級公司,各級公司包括各部門,AbstractOrganization充當抽象構建類,Company充當容器構建類(能夠定義其餘容器構建類),Department充當葉子構建類(能夠定義其餘葉子構建類)。架構
AbstractOrganizationide
public abstract class AbstractOrganization { public abstract void add(AbstractOrganization organization); public abstract void remove(AbstractOrganization organization); public abstract AbstractOrganization getChild(int i); public abstract void notifyMessage(); }
Companythis
public class Company extends AbstractOrganization { private List<AbstractOrganization> organizationList=new ArrayList<>(); private String name; public Company(String name) { this.name = name; } @Override public void add(AbstractOrganization organization) { organizationList.add(organization); } @Override public void remove(AbstractOrganization organization) { organization.remove(organization); } @Override public AbstractOrganization getChild(int i) { return organizationList.get(i); } @Override public void notifyMessage() { System.out.println("對公司:"+name+" 進行通知"); for (AbstractOrganization organization:organizationList){ organization.notifyMessage(); } } }
Department操作系統
public class Department extends AbstractOrganization { private String name; public Department(String name) { this.name = name; } @Override public void add(AbstractOrganization organization) { System.out.println("對不起,不支持該方法!"); } @Override public void remove(AbstractOrganization organization) { System.out.println("對不起,不支持該方法!"); } @Override public AbstractOrganization getChild(int i) { System.out.println("對不起,不支持該方法!"); return null; } @Override public void notifyMessage() { System.out.println("對"+name+" 進行通知"); } }
Client設計
public class Client { public static void main(String[] args) { AbstractOrganization c1,c2,d1,d2,d3; c1=new Company("總公司"); c2=new Company("分公司1"); d1=new Department("總公司部門1"); d2=new Department("分公司部門1"); d3=new Department("分公司部門2"); c1.add(c2); c1.add(d1); c2.add(d2); c2.add(d3); //客戶端無序關心節點的層次結構,對節點能夠進行統一處理 c1.notifyMessage(); System.out.println("-------------"); c2.notifyMessage(); } } //對公司:總公司 進行通知 //對公司:分公司1 進行通知 //對分公司部門1 進行通知 //對分公司部門2 進行通知 //對總公司部門1 進行通知 //------------- //對公司:分公司1 進行通知 //對分公司部門1 進行通知 //對分公司部門2 進行通知
透明組合模式中,抽象構件Component中聲明瞭全部用於管理成員對象的方法,包括add()、remove()以及getChild()等方法,這樣作的好處是確保全部的構件類都有相同的接口。在客戶端看來,葉子對象與容器對象所提供的方法是一致的,客戶端能夠相同地對待全部的對象。
透明組合模式的缺點是不夠安全,由於葉子對象和容器對象在本質上是有區別的。葉子對象不可能有下一個層次的對象,即不可能包含成員對象,所以爲其提供add()、remove()以及getChild()等方法是沒有意義的,這在編譯階段不會出錯,但在運行階段若是調用這些方法可能會出錯(若是沒有提供相應的錯誤處理代碼)。
Java AWT中使用的組合模式就是安全組合模式。
安全組合模式中,在抽象構件Component中沒有聲明任何用於管理成員對象的方法,而是在Composite類中聲明並實現這些方法。這種作法是安全的,由於根本不向葉子對象提供這些管理成員對象的方法,對於葉子對象,客戶端不可能調用到這些方法。
安全組合模式的缺點是不夠透明,由於葉子構件和容器構件具備不一樣的方法,且容器構件中那些用於管理成員對象的方法沒有在抽象構件類中定義,所以客戶端不能徹底針對抽象編程,必須有區別地對待葉子構件和容器構件。
客戶端須要指定具體的容器類型,才能調用管理成員對象的方法。
Comapany c1,c2; AbstractOrganization d1,d2,d3; ... c1.notifyMessage();
組合模式用戶處理相似樹形結構的包含容器對象和葉子對象的層次結構,經過該模式可忽略總體與部分的差別,讓客戶端統一對待它們,同時符合「開閉原則」利於擴展。