設計模式--結構型--組合模式
- 組合模式
- 定義
- 結構
- 案例
- 組合模式的分類
- 優點
- 使用場景
組合模式
定義
又稱部分整體模式,是用于把一組相似的對象當作一個單一的對象。組合模式依據樹型結構來組合對象,用來表示部分以及整體層次,這種類型的設計模式屬于結構型
模式,它創建了對象組的樹型結構。
結構
- 抽象根節點(Component):定義系統各層次對象的共有方法和屬性,可以預定義一些默認行為和屬性。
- 樹枝節點(Composite):定義樹枝節點的行為,存儲子節點,組合樹枝節點和葉子節點形成一個樹型結構。
- 葉子節點(Leaf):葉子節點對象,其下再無分支,是系統層次遍歷的最小單位。
案例
如下圖,我們在訪問別的一些管理系統時,經常可以看到類似的菜單。一個菜單可以包含菜單項,也可以包含帶有其他菜單項的菜單,因此使用組合模式就很恰當。
需求:針對一個菜單,打印出其包含的所有菜單以及菜單項。
- 系統管理
- 菜單管理
- 編輯菜單
- 刪除菜單
- 新增菜單
- 權限配置
- 權限設置
- 新增權限
- 角色管理
- 新增角色
- 刪除角色
類圖:
- 菜單管理
/*** 菜單組件 抽象根節點*/
public abstract class MenuComponent {// 菜單組件的名稱protected String name;// 菜單組件的層級protected int level;// 添加子菜單public void add(MenuComponent menuComponent){throw new UnsupportedOperationException();}// 移除子菜單public void remove(MenuComponent menuComponent){throw new UnsupportedOperationException();}// 獲取指定的子菜單public MenuComponent getChild(int index){throw new UnsupportedOperationException();}// 獲取菜單或者菜單項的名稱public String getName(){return name;}// 打印菜單名稱(包含子菜單和子菜單項)public abstract void print();
}
/*** 菜單類 樹枝節點*/
public class Menu extends MenuComponent {// 菜單可以有多個子菜單或者子菜單項private List<MenuComponent> menuComponentList = new ArrayList<>();// 構造方法public Menu(String name, int level) {this.name = name;this.level = level;}@Overridepublic void add(MenuComponent menuComponent) {menuComponentList.add(menuComponent);}@Overridepublic void remove(MenuComponent menuComponent) {menuComponentList.remove(menuComponent);}@Overridepublic MenuComponent getChild(int index) {return menuComponentList.get(index);}@Overridepublic void print() {// 打印菜單名稱for (int i = 0; i < level; i++) {System.out.print("—");}System.out.println(name);// 打印子菜單或子菜單項名稱for (MenuComponent menuComponent : menuComponentList) {menuComponent.print();}}
}
/*** 菜單項 葉子節點*/
public class MenuItem extends MenuComponent{public MenuItem(String name, int level){this.name = name;this.level = level;}@Overridepublic void print() {for (int i = 0; i < level; i++) {System.out.print("—");}System.out.println(name);}
}
public class Test01 {public static void main(String[] args) {// 創建菜單樹MenuComponent menu1 = new Menu("菜單管理", 2);menu1.add(new MenuItem("編輯菜單", 3));menu1.add(new MenuItem("刪除菜單", 3));menu1.add(new MenuItem("新增菜單", 3));MenuComponent menu2 = new Menu("權限管理", 2);menu2.add(new MenuItem("權限設置", 3));menu2.add(new MenuItem("新增權限", 3));MenuComponent menu3 = new Menu("角色管理", 2);menu2.add(new MenuItem("新增角色", 3));menu2.add(new MenuItem("刪除角色", 3));// 創建一級菜單MenuComponent component = new Menu("系統管理", 1);component.add(menu1);component.add(menu2);component.add(menu3);// 打印菜單名稱(如果有子菜單一起打印)component.print();}
}
組合模式的分類
在使用組合模式時,根據抽象構件類的定義形式,可將組合模式分為透明組合模式和安全組合模式兩種形式。
- 透明組合模式
在透明組合模式中,抽象根節點角色中聲明了所有用于管理成員對象的方法,比如在實例中MenuComponent聲明了add、remove,getChild方法,這樣做的好處是確保所有的構件類都有相同的接口。透明組合模式也是組合模式的標準形式。透明組合模式的缺點是不夠安全,因為葉子節點對象和容器對象在本質上是有區別的,葉子對象不可能有下一個層次的對象,即不可能包含成員對象,因此為其提供add()remove()等方法是沒有意義的,這在編譯階段不會出錯,但是在運行階段如果調用這些方法可能會出錯(如果沒有提供相應的錯誤處理代碼) - 安全組合模式
在安全組合模式中,在抽象構件角色中沒有聲明任何用于管理成員對象的方法,而是在樹枝節點Menu類中聲明并實現這些方法。安全組合模式的缺點時不夠透明,因為葉子構件和容器構件具有不同的方法,且容器構件中那些用于管理成員對象的方法沒有在抽象構件類中定義,因此客戶端不能完全針對抽象編程,必須有區別的對待葉子構件和容器構件。
優點
- 組合模式可以清楚的定義分層次的復雜對象,表示對象的全部或部分層次,它讓客戶端忽略了層次的差異,方便對整個層次結構進行控制。
- 客戶端可以一致的使用一個組合結構或者其中單個對象,不必關系處理的是單個對象還是整個組合結構,簡化客戶端代碼。
- 在組合模式中增加新的樹枝節點和子節點都很方便,無需對現有類庫進行任何修改,符合開閉原則。
- 組合模式為樹型結構的面向對象實現提供了一種靈活的解決方案,通過葉子節點和樹節點的遞歸組合,可以形成復雜的樹型結構,但對樹型結構的控制卻非常簡單。
使用場景
出現樹型結構的地方都可以使用組合模式