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