组合模式(Composite Pattern)

又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示”整体-部分“层次。这种模式使得客户端可以统一处理单个对象和组合对象,而无需关心它们的具体实现。

核心角色

角色 职责
Component 定义所有叶子和组合的公共接口,通常是抽象类或接口
Leaf 表示没有子节点的对象,实现基本操作
Composite 包含子组件的对象,实现容器行为,如添加、删除子组件等

适用场景

  • 需要表示“整体-部分”关系的结构(如文件系统目录与文件、学校组织、管理层级)
  • 希望客户端 以一致方式处理单个对象和组合对象
  • 结构具有层级性,并且可能动态变化。

真实案例

对于某OA系统,中秋节安排了统一假期,但某些部门中秋节必须轮班,但可以节后进行调休申请。另外针对个别人员,比如电工、安防等个别对象需要派一到两个人留守,在节前申报了坚守岗位的名单后,office boy在OA系统上通过拖拽的方式,统一调整的内部员工的假期。

设计如下:

角色 实例 描述
Component AttendanceComponent 考勤
Leaf EmployeeLeaf 员工个人的考勤
Composite DepartmentComposite 整个部门的考勤

组合模式(Composite Pattern)和企业级设计模式的“对象-关系”映射相对应,但这里只讨论代码层面的映射关系,设计如下

其中要求DepartmentComposite将描述为一种树结构,下面是部分代码实现,

Component接口,

1
2
3
4
5
6
7
8
9
public interface AttendanceComponent {

void punchIn();

void punchOut();

// 当日工时
long getAttendance();
}

Leaf叶子节点,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class EmployeeLeaf implements AttendanceComponent {

private long attendance = 0L;

private OffsetDateTime punchInTime;
private OffsetDateTime punchOutTime;

@Override
public void punchIn() {
punchInTime = OffsetDateTime.now();
}

@Override
public void punchOut() {
punchOutTime = OffsetDateTime.now();
}

@Override
public long getAttendance() {
if (attendance == 0 && (punchOutTime != null && punchInTime != null)) {
attendance = Duration.between(punchInTime, punchOutTime).toMinutes();
}
return attendance;
}
}

Composite组合类,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class DepartmentComposite implements AttendanceComponent {

private final Set<AttendanceComponent> components = new HashSet<>();

@Override
public void punchIn() {
for (AttendanceComponent component : components) {
component.punchIn();
}
}

@Override
public void punchOut() {
for (AttendanceComponent component : components) {
component.punchOut();
}
}

@Override
public long getAttendance() {
return components.stream().mapToLong(AttendanceComponent::getAttendance).sum();
}

public void add(AttendanceComponent component) {
components.add(component);
}

public void remove(AttendanceComponent component) {
components.remove(component);
}
}

总结

组合模式(Composite Pattern) 通过继承保持了单一职责原则,通过集合操作实现了“整体-部分”的一致性操作。