
一、介绍
组合模式(Composite Pattern),属于结构型设计模式。组合模式常用于树形的数据结构,比如:多级菜单、部门层级关系、html文本中的dom树。它的特点是使用户对单个对象和组合对象的使用是相同的,也就是说,使用组合模式可以把一个子节点与其父节点统一处理。当我们对一个节点按照某种逻辑进行处理时,与此同时,会以类似递归的形式对其子节点按照相同的逻辑进行处理。
该设计模式主要角色就两种:①抽象接口,②实现类
二、组合模式中的角色
-
抽象类 Component(抽象构件)
在组合模式中,由于类与类之间的结构是树形结构(即上下级关系),因此我们可以对这些类进行无差别地抽象出一个接口类,用于定义各个类的行为,在适当情况下实现所有类共有接口的默认行为。
-
实现类 Leaf(叶子构件)
抽象类中定义了行为,因此我们可以对该抽象类定义不同的子类,对该行为实现不同的逻辑
-
组合类 (组合构件)
对不同的实现类进行实例化后,按照树形的结构对其进行组合。当对一个节点调用抽象类定义的方法时,按照类似递归的方式,也对其所有子孙节点进行调用。以实现对父节点和子节点的统一处理。定义有子部件的那些部件的行为,存储子部件,在Component接口中实现与子部件有关的操作。
三、核心思想
- 统一接口:叶子节点和组合节点使用相同的接口
- 递归结构:支持树形结构的递归操作
- 透明性:客户端无需区分叶子节点和组合节点
- 整体-部分:将部分对象组合成整体对象
四、案例一
我们以公司员工为例 ,不同的员工可向下管理多个员工,而每一个员工都有一个共同的动作:领工资。
java
public interface Employ {
/**
* 领工资
*/
void getSalary();
/**
* 添加员工
*/
void addEmployee(Employ employ);
/**
* 获取当前员工可管理的员工
*/
List<Employ> children();
}
添加员工实现类(EmployImpl):
java
public class EmployImpl implements Employ{
// 员工姓名
private String name;
// 员工工资
private String salary;
// 可管理的员工集合
private List<Employ> employList = new ArrayList<>();
// 通过姓名和薪资实例化一个员工
public EmployImpl(String name, String salary) {
this.name = name;
this.salary = salary;
}
// 领工资
@Override
public void getSalary() {
System.out.println("员工姓名:" + name + ",领取工资:" + salary);
// 管理的员工集合也领工资
for (Employ employ : employList) {
employ.getSalary();
}
}
// 添加一个员工
@Override
public void addEmployee(Employ employ) {
employList.add(employ);
}
// 获取管理的员工集合
@Override
public List<Employ> children() {
return employList;
}
@Override
public String toString() {
return name;
}
}
测试

五、案例二
Component(抽象构件)
java
// 抽象组件
public abstract class Node {
// 抽象的组件对象,为组合中的对象声明接口,实现接口的缺省行为
abstract public void p();
}
Leaf(叶子构件)
java
public class LeafNode extends Node {
String name;
public LeafNode(String name) {this.name = name;}
@Override
public void p() {
System.out.println(name);
}
}
Composite(组合构件)
java
public class BranchNode extends Node{
List<Node> nodes = new ArrayList<>();
String name;
public BranchNode(String name) {this.name = name;}
public void add(Node n) {
nodes.add(n);
}
@Override
public void p() {
System.out.println(name);
}
}
客户调用
java
public class Test {
public static void main(String[] args) {
BranchNode root = new BranchNode("root");
BranchNode chapter1 = new BranchNode("chapter1");
BranchNode chapter2 = new BranchNode("chapter2");
Node chapter3 = new LeafNode("chapter3");
Node c11 = new LeafNode("c31");
Node c12 = new LeafNode("c32");
BranchNode b21 = new BranchNode("section21");
Node c211 = new LeafNode("c211");
Node c212 = new LeafNode("c212");
root.add(chapter1);
root.add(chapter2);
root.add(chapter3);
chapter1.add(c11);
chapter1.add(c12);
chapter2.add(b21);
b21.add(c211);
b21.add(c212);
tree(root, 0);
}
static void tree(Node b, int depth) {
for(int i=0; i<depth; i++) System.out.print("--");
b.p();
if(b instanceof BranchNode) {
for (Node n : ((BranchNode)b).nodes) {
tree(n, depth + 1);
}
}
}
}
输出

六、优缺点
核心优势
- 统一接口:叶子节点和组合节点使用相同接口
- 递归结构:支持树形结构的递归操作
- 透明性:客户端无需区分叶子节点和组合节点
- 扩展性:易于添加新的叶子节点和组合节点
注意事项
- 性能考虑:深层递归可能影响性能
- 内存管理:复杂结构需要注意内存泄漏
- 设计复杂度:增加了系统的复杂度
- 类型安全:透明式模式可能产生运行时异常
七、总结
组合模式是一种重要的结构型设计模式,它通过将对象组合成树形结构,实现了部分-整体的层次结构,并提供了统一的接口