组合模式
概念
组合模式(Composite Pattern)是一种结构型设计模式,允许你将对象组合成树形结构以表示"部分-整体"的层次结构。组合模式使得客户端可以统一对待单个对象和组合对象。
应用场景
- 树形结构表示:适用于需要以树形结构表示对象层次的场景,例如文件系统、组织结构图、UI组件树等。
- 处理部分和整体的一致性:在需要统一处理单个对象和组合对象的情况下,组合模式可以简化客户端代码,因为客户端无需关心处理的对象是单个还是组合对象。
- 递归操作:适用于需要对树形结构中的所有节点进行递归操作的场景,例如遍历整个树形结构、计算总值、查找等。
注意点
- 透明性与安全性权衡:组合模式有两种实现方式,透明组合和安全组合。透明组合允许所有组件具有相同接口,操作更统一,但会有不适用的操作(如对叶子节点调用添加子节点的操作)。安全组合则为叶子和组合节点提供不同接口,但操作灵活性降低。
- 性能问题:由于组合模式需要递归地处理整个树形结构,因此在大规模树形结构中可能存在性能问题。
- 节点间的职责分配:确保合理分配叶子节点和组合节点的职责,避免职责不明确。
核心要素
- Component(抽象构件):定义叶子节点和组合节点的共同接口。
- Leaf(叶子节点):表示树形结构的基本元素,不包含子节点。
- Composite(组合节点):表示有子节点的复杂元素,包含添加、删除和遍历子节点的功能。
- 统一处理:客户端可以统一处理单个对象和组合对象。
Java代码完整示例
java
// 抽象构件
interface Component {
void operation();
}
// 叶子节点
class Leaf implements Component {
private String name;
public Leaf(String name) {
this.name = name;
}
@Override
public void operation() {
System.out.println("叶子 " + name + " 被访问");
}
}
// 组合节点
class Composite implements Component {
private List<Component> children = new ArrayList<>();
public void add(Component component) {
children.add(component);
}
public void remove(Component component) {
children.remove(component);
}
public Component getChild(int i) {
return children.get(i);
}
@Override
public void operation() {
System.out.println("组合节点被访问");
for (Component child : children) {
child.operation();
}
}
}
// 客户端
public class Client {
public static void main(String[] args) {
// 创建叶子节点
Leaf leaf1 = new Leaf("1");
Leaf leaf2 = new Leaf("2");
Leaf leaf3 = new Leaf("3");
// 创建组合节点
Composite composite = new Composite();
composite.add(leaf1);
composite.add(leaf2);
Composite root = new Composite();
root.add(composite);
root.add(leaf3);
// 统一调用组合结构
root.operation();
}
}
输出:
组合节点被访问
组合节点被访问
叶子 1 被访问
叶子 2 被访问
叶子 3 被访问
各种变形用法完整示例
-
透明组合模式
在这种实现方式中,叶子和组合节点共享相同的接口,客户端可以透明地使用组合和叶子对象。
代码示例:
java// 抽象构件(透明组合) interface Component { void operation(); void add(Component component); void remove(Component component); Component getChild(int i); } // 叶子节点(透明组合) class Leaf implements Component { private String name; public Leaf(String name) { this.name = name; } @Override public void operation() { System.out.println("叶子 " + name + " 被访问"); } @Override public void add(Component component) { throw new UnsupportedOperationException("叶子节点不支持添加操作"); } @Override public void remove(Component component) { throw new UnsupportedOperationException("叶子节点不支持删除操作"); } @Override public Component getChild(int i) { throw new UnsupportedOperationException("叶子节点没有子节点"); } } // 组合节点(透明组合) class Composite implements Component { private List<Component> 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); } @Override public Component getChild(int i) { return children.get(i); } } // 客户端 public class ClientTransparentComposite { public static void main(String[] args) { Component leaf1 = new Leaf("1"); Component leaf2 = new Leaf("2"); Component leaf3 = new Leaf("3"); Composite composite = new Composite(); composite.add(leaf1); composite.add(leaf2); Composite root = new Composite(); root.add(composite); root.add(leaf3); root.operation(); } }
-
安全组合模式
在安全组合模式下,叶子节点和组合节点有各自不同的接口,避免了客户端对叶子节点调用不适用的操作。
代码示例:
java// 抽象构件 interface Component { void operation(); } // 叶子节点(安全组合) class Leaf implements Component { private String name; public Leaf(String name) { this.name = name; } @Override public void operation() { System.out.println("叶子 " + name + " 被访问"); } } // 组合节点(安全组合) class Composite implements Component { private List<Component> children = new ArrayList<>(); public void add(Component component) { children.add(component); } public void remove(Component component) { children.remove(component); } public Component getChild(int i) { return children.get(i); } @Override public void operation() { System.out.println("组合节点被访问"); for (Component child : children) { child.operation(); } } } // 客户端 public class ClientSafeComposite { public static void main(String[] args) { Leaf leaf1 = new Leaf("1"); Leaf leaf2 = new Leaf("2"); Leaf leaf3 = new Leaf("3"); Composite composite = new Composite(); composite.add(leaf1); composite.add(leaf2); Composite root = new Composite(); root.add(composite); root.add(leaf3); root.operation(); } }
-
组合模式与职责链模式结合
组合模式与职责链模式可以结合使用,使得组合结构的每个节点都有机会处理请求。
代码示例:
java// 抽象构件 interface Component { void operation(); void setNext(Component next); } // 叶子节点(与职责链模式结合) class Leaf implements Component { private String name; private Component next; public Leaf(String name) { this.name = name; } @Override public void operation() { System.out.println("叶子 " + name + " 被访问"); if (next != null) { next.operation(); } } @Override public void setNext(Component next) { this.next = next; } } // 组合节点 class Composite implements Component { private List<Component> children = new ArrayList<>(); private Component next; public void add(Component component) { children.add(component); } @Override public void operation() { System.out.println("组合节点被访问"); for (Component child : children) { child.operation(); } if (next != null) { next.operation(); } } @Override public void setNext(Component next) { this.next = next; } } // 客户端 public class ClientChainComposite { public static void main(String[] args) { Leaf leaf1 = new Leaf("1"); Leaf leaf2 = new Leaf("2"); Composite composite = new Composite(); composite.add(leaf1); composite.add(leaf2); Leaf leaf3 = new Leaf("3"); composite.setNext(leaf3); composite.operation(); } }
这些示例展示了组合模式的基本用法及其多种变形。