組合模式(Composite)的安全模式與透明模式

技術小阿哥發表於2017-11-27

組合模式(Composite):將物件組合成樹形結構以表示“部分-整體”的層次結構,使得使用者對單個物件和組合物件的使用具有一致性。

使用場景:

1、用於物件的部分-整體層次結構,如樹形選單、資料夾選單、部門組織架構圖等;

2、對使用者隱藏組合物件與單個物件的不同,使得使用者統一地使用組合結構中的所有物件。

通用類圖:

 

說到樹,“資料結構”這門課上都學習過了,樹的遍歷問題最重要了。下面按照類圖直接用簡單的程式碼實現一番。

// 抽象構件類、節點類
abstract class Component {
	public String name;

	public Component(String name) {
		this.name = name;
	}

	// 公有操作
	public void getName() {
		System.out.println(this.name);
	}
}


// 樹枝構件類
class Composite extends Component {

	private LinkedList<Component> children;

	public Composite(String name) {
		super(name);
		this.children = new LinkedList<Component>();
	}

	// 新增一個節點,可能是樹枝、葉子
	public void add(Component child) {
		this.children.add(child);
	}

	// 刪除一個節點,可能是樹枝、葉子
	public void remove(String child) {
		this.children.remove(child);
	}

	// 獲取子樹
	public LinkedList<Component> getChildren() {
		return this.children;
	}
}


// 樹葉構件類
class Leaf extends Component {

	public Leaf(String name) {
		super(name);
	}
}


// 測試類,負責構建整棵樹
public class Client {
	public static void main(String[] args) {

		Composite root = new Composite("樹根");

		Composite branch01 = new Composite("樹枝01");
		Composite branch02 = new Composite("樹枝02");

		root.add(branch01);
		root.add(branch02);

		Component leaf01 = new Leaf("樹葉01");
		Component leaf02 = new Leaf("樹葉02");
		Component leaf03 = new Leaf("樹葉03");
		Component leaf04 = new Leaf("樹葉04");
		Component leaf05 = new Leaf("樹葉05");

		branch01.add(leaf01);
		branch01.add(leaf02);

		branch02.add(leaf03);
		branch02.add(leaf04);
		branch02.add(leaf05);
		
		displayTree(root);

	}

	// 遞迴遍歷整棵樹
	public static void displayTree(Composite root) {
		LinkedList<Component> children = root.getChildren();

		for (Component c : children) {
			if (c instanceof Leaf) {
				System.out.print("	");
				c.getName();
			} else {
				c.getName();
				// 遞迴
				displayTree((Composite)c);
			}
		}
	}
}


測試結果:

樹枝01
	樹葉01
	樹葉02
樹枝02
	樹葉03
	樹葉04
	樹葉05


上面的 Client 類構建樹的程式碼讓人看了覺得煩,如果整棵樹下來有幾百個節點,這樣子的工作效率太糟糕了。其實,在實際應用中,並不是這樣子手工地構建一棵複雜的樹的,應該是我們已經將整棵樹的節點內容、邏輯關係都儲存在資料庫表中(更重要的是這錄入工作應該不是我們開發人員做的),由於表中的各個節點記錄都儲存有自身的一些相關資訊,包括是否為樹葉、父節點等等,開發人員需要的就是讓程式從資料庫中的表中讀取記錄來構建整棵樹

此外,上面的程式碼中只能從根節點往下遍歷,不能夠從某一節點開始往上遍歷,解決這個問題可以在抽象構件類 Component 類中新增一個 parent 屬性,再新增相應 setParent()  、 getParent()方法即可。而關於不同的遍歷方法再具體實現一下就完成了。

上面的類圖是屬於安全模式的,因為 Leaf 類不具有 add 、 remove 等方法,這些具體方法是被下置到 Composite 類(樹枝節點類)中去具體實現了。

如果要實現透明模式,類圖如下:

 

差別僅在於將 add 、remove 等方法上升到抽象構件類 Component 中去了。那麼此時 Leaf 類在具體實現時就必須將繼承而來的 add 、remove 等不可用、不合邏輯的方法給註解 Deprecated 掉,並丟擲適當的異常,不提供給使用者使用。看起來這種透明模式似乎更加麻煩,沒事找事。其實,這種模式下使得我們在遍歷整棵樹的時候可以不進行強制型別轉換。看看上面的 displayTree() 方法,裡面在使用遞迴遍歷時就使用到了 (Composite)c 強制型別轉換了。

Leaf 類程式碼如下:

// 樹葉構件類
class Leaf extends Component {

	public Leaf(String name) {
		super(name);
	}
	
	@Deprecated // 丟擲不支援的操作異常
	public void add(Component child) throws UnsupportedOperationException{
		throws new UnsupportedOperationException();
	}

	@Deprecated
	public void remove(String child) throws UnsupportedOperationException{
		throws new UnsupportedOperationException();
	}

	@Deprecated
	public LinkedList<Component> getChildren() throws UnsupportedOperationException{
		throws new UnsupportedOperationException();
	}
}


具體怎麼使用安全模式或透明模式,看具體情況咯。



本文轉自 xxxx66yyyy 51CTO部落格,原文連結:http://blog.51cto.com/haolloyin/347308,如需轉載請自行聯絡原作者


相關文章