组合模式
组合(Composite Pattern)模式(整体-部分(Part-Whole)模式),是一种将对象组合成树状的层次结构的模式,用来表示“整体-部分”的关系,使用户对单个对象和组合对象具有一致的访问性,属于结构型设计模式。
组合模式一般用来描述整体与部分的关系,它将对象组织到树形结构中,顶层的节点被称为根节点,根节点下面可以包含树枝节点和叶子节点,树枝节点下面又可以包含树枝节点和叶子节点,树形结构图如下

根节点和树枝节点本质上属于同一种数据类型,可以作为容器使用;而叶子节点与树枝节点在语义上不属于用一种类型。但是在组合模式中,会把树枝节点和叶子节点看作属于同一种数据类型(用统一接口定义),让它们具备一致行为。
组合模式优点:
- 组合模式使得客户端代码可以一致地处理单个对象和组合对象,无须关心自己处理的是单个对象,还是组合对象,这简化了客户端代码;
- 更容易在组合体内加入新的对象,客户端不会因为加入了新的对象而更改源代码,满足“开闭原则”;
其主要缺点是:
- 设计较复杂,客户端需要花更多时间理清类之间的层次关系;
- 不容易限制容器中的构件;
- 不容易用继承的方法来增加构件的新功能;
组合模式的结构
- 抽象构件(Component)角色:作用是为树叶构件和树枝构件声明公共接口,并实现它们的默认行为。在透明式的组合模式中抽象构件还声明访问和管理子类的接口;在安全式的组合模式中不声明访问和管理子类的接口,管理工作由树枝构件完成。(总的抽象类或接口,定义一些通用的方法,比如新增、删除)
- 树叶构件(Leaf)角色:是组合中的叶节点对象,没有子节点,用于继承或实现抽象构件。
- 树枝构件(Composite)角色 / 中间构件:是组合中的分支节点对象,它有子节点,用于继承和实现抽象构件。主要作用是存储和管理子部件,通常包含 Add()、Remove()、GetChild() 等方法。

public abstract class MenuComponent { protected String name; protected int level; public void add(MenuComponent component) { throw new UnsupportedOperationException(); } public void remove(MenuComponent component) { throw new UnsupportedOperationException(); } public MenuComponent getChild(int i) { throw new UnsupportedOperationException(); } public String getName() { return name; } public void print() { throw new UnsupportedOperationException(); } }
Menu类实现了除getName方法的其他所有方法,因为Menu类具有添加菜单,移除菜单和获取子菜单的功能
public class Menu extends MenuComponent { private List<MenuComponent> menuComponentList = new ArrayList<>(); public Menu(String name, int level) { this.name = name; this.level = level; this.menuComponentList = new ArrayList<>(); } @Override public void add(MenuComponent component) { menuComponentList.add(component); } @Override public void remove(MenuComponent component) { menuComponentList.remove(component); } @Override public MenuComponent getChild(int i) { return menuComponentList.get(i); } @Override public void print() { for (int i = 0; i < level; i++) { System.out.println("--"); } System.out.println(name); for (MenuComponent component : menuComponentList) { component.print(); } } }
MenuItem是菜单项,不能再有子菜单,所以添加菜单,移除菜单和获取子菜单的功能并不能实现。
public class MenuItem extends MenuComponent { public MenuItem(String name, int level) { this.name = name; this.level = level; } @Override public void print() { for (int i = 0; i < level; i++) { System.out.println("--"); } System.out.println(name); } }
测试类
public class MenuTest { public static void main(String[] args) { MenuComponent systemManager = new Menu("系统管理", 0); MenuComponent menuManager = new Menu("菜单管理", 1); MenuItem view = new MenuItem("查看", 2); MenuItem edit = new MenuItem("编辑", 2); menuManager.add(view); menuManager.add(edit); systemManager.add(menuManager); MenuComponent permissionManager = new Menu("权限管理", 1); MenuItem add = new MenuItem("添加权限", 2); MenuItem remove = new MenuItem("移除权限", 2); permissionManager.add(add); permissionManager.add(remove); systemManager.add(permissionManager); MenuComponent soleManager = new Menu("角色管理", 1); MenuItem addSole = new MenuItem("添加角色", 2); soleManager.add(addSole); MenuItem editSole = new MenuItem("编辑角色", 2); soleManager.add(editSole); systemManager.add(soleManager); systemManager.print(); } }
立志如山 静心求实
浙公网安备 33010602011771号