一、实现方式
组合模式通过树形结构统一处理单个对象(叶节点)和组合对象(容器节点),其核心实现分为透明式和安全式两种方式,具体如下:
- 透明式实现
- 抽象构件(Component):定义统一接口,包含操作方法(如
operation()
)和子节点管理方法(如add()
、remove()
)。 - 叶子节点(Leaf):实现抽象构件接口,对子节点管理方法抛出异常(如
UnsupportedOperationException
)。 - 容器节点(Composite):实现抽象构件接口,管理子节点列表,递归调用子节点操作。
示例代码:
java
// 抽象构件
public interface Component {
void operation();
void add(Component component);
void remove(Component component);
}
// 叶子节点
public class Leaf implements Component {
@Override
public void operation() {
System.out.println("执行叶节点操作");
}
// 抛出异常
@Override
public void add(Component component) {
throw new UnsupportedOperationException();
}
@Override
public void remove(Component component) {
throw new UnsupportedOperationException();
}
}
// 容器节点
public class Composite implements Component {
private List children = new ArrayList<>();
@Override
public void operation() {
System.out.println("执行容器操作");
for (Component child : children) {
child.operation();
}
}
@Override
public void add(Component component) {
children.add(component);
}
@Override
public void remove(Component component) {
children.remove(component);
}
}
- 安全式实现
- 抽象构件(Component):仅定义操作方法(如
operation()
),不包含子节点管理方法。 - 容器节点(Composite):扩展抽象构件,新增子节点管理方法(如
add()
、remove()
)。 - 叶子节点(Leaf):直接实现抽象构件接口,无需处理子节点操作。
示例代码:
java
// 抽象构件
public abstract class Component {
public abstract void operation();
}
// 容器节点
public class Composite extends Component {
private List children = new ArrayList<>();
public void add(Component component) {
children.add(component);
}
public void remove(Component component) {
children.remove(component);
}
@Override
public void operation() {
System.out.println("执行容器操作");
for (Component child : children) {
child.operation();
}
}
}
// 叶子节点
public class Leaf extends Component {
@Override
public void operation() {
System.out.println("执行叶节点操作");
}
}
二、测试方法
测试组合模式需验证树形结构的构建、节点操作的统一性及递归调用的正确性,主要通过单元测试和集成测试实现。
- 单元测试:验证节点操作
- 目标:确保叶节点和容器节点的
operation()
方法正确执行。 - 测试用例:
- 测试叶节点单独调用
operation()
。 - 测试容器节点调用
operation()
时递归执行子节点操作。
示例(JUnit):
- 测试叶节点单独调用
java
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class CompositeTest {
@Test
public void testLeafOperation() {
Component leaf = new Leaf();
leaf.operation(); // 预期输出:执行叶节点操作
}
@Test
public void testCompositeOperation() {
Component composite = new Composite();
composite.add(new Leaf());
composite.add(new Leaf());
composite.operation();
// 预期输出:执行容器操作 + 两次叶节点操作
}
}
- 集成测试:验证树形结构
- 目标:测试多层嵌套的树形结构及节点管理方法(如
add()
、remove()
)。 - 测试用例:
- 构建多级容器节点,验证操作递归执行。
- 测试节点的添加和删除是否影响结构。
示例(Testcontainers + JUnit):
java
@Test
public void testMultiLevelComposite() {
Component root = new Composite();
Component branch = new Composite();
root.add(branch);
branch.add(new Leaf());
root.operation();
// 预期输出:根容器操作 → 分支容器操作 → 叶节点操作
}
- 异常场景测试
- 目标:验证透明式实现中叶节点调用子节点管理方法时的异常处理。
- 测试用例:
- 调用叶节点的
add()
或remove()
方法,验证是否抛出UnsupportedOperationException
。
示例:
- 调用叶节点的
java
@Test
public void testLeafAddOperation() {
Component leaf = new Leaf();
assertThrows(UnsupportedOperationException.class, () -> leaf.add(new Leaf()));
}
- 性能测试(可选)
- 目标:测试递归调用的性能,避免栈溢出或效率问题。
- 测试用例:
- 构建深度较大的树形结构,测量操作执行时间。
三、测试注意事项
- 覆盖所有节点类型:测试叶节点、单层容器、多层嵌套容器的组合。
- 验证操作一致性:确保客户端无需区分叶节点和容器节点,统一调用接口。
- 依赖注入:通过构造函数或工厂方法注入节点,避免硬编码。
- 数据隔离:使用测试容器(如Testcontainers)模拟数据库或外部依赖。
四、总结
组合模式的实现需根据场景选择透明式或安全式,测试则需覆盖操作一致性、节点管理及异常处理。通过单元测试和集成测试,可确保树形结构的正确性与扩展性,同时避免设计漏洞。