結構型模式-組合模式(樹形結構的處理)

[Toc]java

樹形結構在軟件中隨處可見,例如操做系統中的目錄結構、應用軟件中的菜單、辦公系統中的公司組織結構等。git

組合模式經過一種巧妙的設計方案使得用戶能夠一致性地處理整個樹形結構或者樹形結構的一部分,也能夠一致性地處理樹形結構中的葉子節點(不包含子節點的節點)和容器節點(包含子節點的節點)。編程

1. 定義

組合模式(Composite Pattern):組合多個對象造成樹形結構以表示具備「總體—部分」關係的層次結構。組合模式對單個對象(即葉子對象)和組合對象(即容器對象)的使用具備一致性,組合模式又能夠稱爲「總體—部分」(Part-Whole)模式,它是一種對象結構型模式。設計模式

2. 結構

在組合模式中引入了抽象構件類Component,它是全部容器類和葉子類的公共父類,客戶端針對Component進行編程。組合模式結構如圖所示:安全

組合模式

  • Component(抽象構件):它能夠是接口或抽象類,爲葉子構件和容器構件對象聲明接口,在該角色中能夠包含全部子類共有行爲的聲明和實現。在抽象構件中定義了訪問及管理它的子構件的方法,如增長子構件、刪除子構件、獲取子構件等。
  • Leaf(葉子構件):它在組合結構中表示葉子節點對象,葉子節點沒有子節點,它實現了在抽象構件中定義的行爲。對於那些訪問及管理子構件的方法,能夠經過異常等方式進行處理。
  • Composite(容器構件):它在組合結構中表示容器節點對象,容器節點包含子節點,其子節點能夠是葉子節點,也能夠是容器節點,它提供一個集合用於存儲子節點,實現了在抽象構件中定義的行爲,包括那些訪問及管理子構件的方法,在其業務方法中能夠遞歸調用其子節點的業務方法。

3. 代碼實現

代碼實現了一個公司的組織架構,包括各級公司,各級公司包括各部門,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 進行通知

4. 透明組合模式與安全組合模式

4.1 透明組合模式

透明組合模式中,抽象構件Component中聲明瞭全部用於管理成員對象的方法,包括add()、remove()以及getChild()等方法,這樣作的好處是確保全部的構件類都有相同的接口。在客戶端看來,葉子對象與容器對象所提供的方法是一致的,客戶端能夠相同地對待全部的對象。

透明組合模式的缺點是不夠安全,由於葉子對象和容器對象在本質上是有區別的。葉子對象不可能有下一個層次的對象,即不可能包含成員對象,所以爲其提供add()、remove()以及getChild()等方法是沒有意義的,這在編譯階段不會出錯,但在運行階段若是調用這些方法可能會出錯(若是沒有提供相應的錯誤處理代碼)。

4.1 安全組合模式

Java AWT中使用的組合模式就是安全組合模式。

安全組合模式中,在抽象構件Component中沒有聲明任何用於管理成員對象的方法,而是在Composite類中聲明並實現這些方法。這種作法是安全的,由於根本不向葉子對象提供這些管理成員對象的方法,對於葉子對象,客戶端不可能調用到這些方法。

安全組合模式的缺點是不夠透明,由於葉子構件和容器構件具備不一樣的方法,且容器構件中那些用於管理成員對象的方法沒有在抽象構件類中定義,所以客戶端不能徹底針對抽象編程,必須有區別地對待葉子構件和容器構件。

客戶端須要指定具體的容器類型,才能調用管理成員對象的方法。

Comapany c1,c2;
AbstractOrganization d1,d2,d3;
...
c1.notifyMessage();

5. 優缺點

  • 優勢
  1. 組合模式能夠清楚地定義分層次的複雜對象,表示對象的所有或部分層次,它讓客戶端忽略了層次的差別,方便對整個層次結構進行控制。
  2. 客戶端能夠一致地使用一個組合結構或其中單個對象,簡化客戶端代碼。
  3. 在組合模式中增長新的容器構件和葉子構件都很方便,無須對現有類庫進行任何修改,符合「開閉原則」。
  4. 組合模式爲樹形結構的面向對象實現提供了一種靈活的解決方案,經過葉子對象和容器對象的遞歸組合,能夠造成複雜的樹形結構,但對樹形結構的控制卻很是簡單。
  • 缺點
  1. 在增長新構件時很難對容器中的構件類型進行限制。由於它們都來自於相同的抽象層,在這種狀況下,必須經過在運行時進行類型檢查來實現,這個實現過程較爲複雜。

6. 適用場景

  1. 在具備總體和部分的層次結構中,但願經過一種方式忽略總體與部分的差別,客戶端能夠一致地對待它們。
  2. 在一個使用面嚮對象語言開發的系統中須要處理一個樹形結構
  3. 在一個系統中可以分離出葉子對象和容器對象,並且它們的類型不固定,須要增長一些新的類型。

7. 我的理解

組合模式用戶處理相似樹形結構的包含容器對象和葉子對象的層次結構,經過該模式可忽略總體與部分的差別,讓客戶端統一對待它們,同時符合「開閉原則」利於擴展。

參考

  1. Java設計模式-劉偉
相關文章
相關標籤/搜索