組合模式-系統菜單的設計

這是我參與8月更文挑戰的第14天,活動詳情查看:8月更文挑戰java


1. 系統菜單的設計

「系統菜單」應該是全部ERP系統都必備的一個基礎模塊,反正我是沒見過哪一個ERP系統是沒有菜單設計的。典型的設計就是一個「樹狀結構」,數據庫表用一個parent_id來構建整棵菜單樹。 既然「菜單設計」如此重要,那麼今天就來說講如何利用「組合模式」來優雅的設計系統菜單。數據庫

菜單分爲兩類:菜單目錄和具有URL地址可點擊的菜單,即樹枝節點和樹葉節點。分別設計Branch類表明菜單目錄,Leaf類表明菜單,類圖以下,很是簡單。 在這裏插入圖片描述 Branch安全

public class Branch {
	private String name;
	private String icon;
	private List children;

	// 省略全參構造函數

	public void add(Branch branch) {
		this.children.add(branch);
	}

	public void add(Leaf leaf) {
		this.children.add(leaf);
	}

	public void print(){
	    System.out.println("name:" + name + ",icon:" + icon);
	}

	public List getChildren() {
	    return children;
	}
}
複製代碼

Leafmarkdown

public class Leaf {
	private String name;
	private String icon;
	private String url;

	// 省略全參構造函數
        // 省略print()
}
複製代碼

客戶端構建菜單樹,代碼省略。。。函數

如此,一棵菜單樹構建出來了,客戶端也能進行遍歷了,可是會發現代碼實現的特別彆扭啊,一點也不優雅。BranchLeaf存在冗餘屬性和代碼啊,無論是目錄仍是菜單,nameicon都是有的,應該提取出Menu抽象類,菜單只是一個抽象,我無論你是樹枝節點仍是樹葉節點,你都是菜單啊。樹枝節點能夠包含樹枝和樹葉,樹葉節點就僅僅包含自身的屬性特徵,這些區別能夠放到子類作特殊處理,可是對於客戶端來講,他們應該都是Menupost

從新設計一下類,優化後的類圖以下: 在這裏插入圖片描述 編寫Menu類,將菜單抽象出來,提取公共屬性和方法:優化

public abstract class Menu {
	protected String name;
	protected String icon;

	// 省略全參構造函數
        // 省略print()
}
複製代碼

樹枝節點Branchthis

public class Branch extends Menu {
	private List<Menu> children = new ArrayList<>();

	public Branch(String name, String icon) {
		super(name, icon);
	}

	public void add(Menu menu) {
		children.add(menu);
	}

	public List<Menu> getChildren() {
		return children;
	}
}
複製代碼

樹葉節點Leafurl

public class Leaf extends Menu{
	private String url;

	// 省略全參構造函數
        // 省略print()
}
複製代碼

2. 組合模式的定義

將對象組合成樹形結構以表示「部分-總體」的層次結構,使得用戶對單個對象和組合對象的使用具備一致性。spa

在這裏插入圖片描述

組合模式通用類圖
  • Component:抽象組件,提取公共的方法和屬性。
  • Leaf:葉子節點,沒有分支,遍歷的最小單位。
  • Composite:樹枝節點,複雜對象,組合樹枝和樹葉造成樹狀結構。

組合模式又被稱爲「部分-總體模式」,只要你須要維護「部分-總體」的關係,例如:樹形菜單,文件菜單等就能夠考慮使用組合模式。

細心的讀者可能已經發現了,客戶端在遍歷整棵樹時,須要判斷遍歷的節點是樹枝仍是樹葉,說白了,客戶端須要知道具體的實現,這實際上是對「依賴倒置原則」的破壞,不過能夠經過「透明模式」來解決。

3. 組合模式的優缺點

優勢

  1. 高層模塊調用簡單,整棵樹中全部的節點都是Component抽象,高層模塊不關心本身處理的是簡單對象仍是複雜對象,統一了客戶端處理節點的方式。
  2. 屏蔽了節點實現細節對高層模塊的影響,能夠隨時加入新的節點。
  3. 節點能夠自由增長,擴展性高。

缺點 仔細看看上面的代碼,客戶端在遍歷樹時,直接使用了實現類,這違反了「依賴倒置原則」。

4. 透明的組合模式

上述實現採用的是「安全模式」,安全模式將樹枝和樹葉的功能區分開了,只有樹枝才能進行組合。 透明模式則是將組合使用的方法所有放到了抽象組件中,這樣無論是樹枝對象仍是樹葉對象,都具備相同的結構,這種方式須要客戶端判斷子類類型,操做不當容易致使異常。 在這裏插入圖片描述

透明的組合模式通用類圖

將組合方法提取到抽象Menu類中,默認不支持組合操做,Branch重寫父類方法,實現組合功能,Leaf不重寫,由於葉子節點自己確實不支持組合操做。

public abstract class Menu {
	protected String name;
	protected String icon;

	// 省略全參構造函數

	public void add(Menu menu){
		// 默認不支持操做
		throw new UnsupportedOperationException();
	}

	public List<Menu> getChildren(){
		// 默認不支持操做
		throw new UnsupportedOperationException();
	}
}
複製代碼

這樣,無論是Branch仍是Leaf,結構上它們都是相同的,只是各自的實現不同而已。

5. 總結

組合模式在項目中隨處可見:樹形菜單、文件系統結構、XML結構等都是樹形結構,均可以優先考慮使用組合模式來實現。 組合模式用於將多個對象組合成樹形結構以表示「總體-部分」的結構層次,組合模式使得客戶端對簡單對象和複雜對象的使用具備一致性,方便了客戶端的調用。

相關文章
相關標籤/搜索