定义
将对象组合成树形结构以表示“部分整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
有时候又叫做部分-整体模式,它使我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以像处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。
比较常见的有文件系统:文件系统由目录和文件组成。每个目录都可以装内容。目录的内容可以是文件,也可以是目录。按照这种方式,计算机的文件系统就是以递归结构来组织的。如果你想要描述这样的数据结构,那么你可以使用组合模式。
另外如果使用过Flash,会知道Flash所使用的显示列表就是一个树形结构,每个显示容器都可以包含任意多的显示对象,而显示对象又可以是显示容器。
UML
优点
- 使客户端调用简单,客户端可以一致的使用组合结构或其中单个对象,用户就不必关心自己处理的是单个对象还是整个组合结构,这就简化了客户端代码。
- 更容易在组合体内加入对象部件. 客户端不必因为加入了新的对象部件而更改代码。这一点符合开闭原则的要求,对系统的二次开发和功能扩展很有利。
缺点
- 组合模式不容易限制组合中的构件。
应用场景
- 当你发现需求中是体现部分与整体层次的结构时,以及你希望可以忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象时,就应该考虑使用组合模式了。
- 你想表示对象的部分-整体层次结构。
- 你希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。
示例
使用组合模式构建一个树形结构。
Java
1 import java.util.ArrayList; 2 import java.util.List; 3 4 public class Main 5 { 6 public static void main(String[] args) 7 { 8 try 9 { 10 //所有结点都使用基类类型定义 11 Component root = new Composite(); 12 13 Component c1 = new Composite(); 14 Component c2 = new Composite(); 15 16 Component leaf1 = new Leaf(); 17 Component leaf2 = new Leaf(); 18 Component leaf3 = new Leaf(); 19 20 //添加到树形结构上 21 root.addChild(c1); 22 root.addChild(leaf1); 23 24 c1.addChild(leaf2); 25 c1.addChild(c2); 26 27 c2.addChild(leaf3); 28 29 //执行指定的一个叶子结点 30 root.getChildAt(0).getChildAt(1).getChildAt(0).doSomething(); 31 } 32 catch (Exception e) 33 { 34 e.printStackTrace(); 35 } 36 } 37 38 /** 39 * 组合组件的基类, 所有树形结构上的结点都必须继承自该类 40 */ 41 public static abstract class Component 42 { 43 public abstract void addChild(Component child) throws Exception; 44 public abstract Component getChildAt(int index) throws Exception; 45 public abstract void removeChild(Component child) throws Exception; 46 public abstract void doSomething(); 47 } 48 49 /** 50 * 容器类 51 */ 52 public static class Composite extends Component 53 { 54 private List<Component> _children; 55 56 public Composite() 57 { 58 _children = new ArrayList<>(); 59 } 60 61 @Override 62 public void addChild(Component child) 63 { 64 _children.add(child); 65 } 66 67 @Override 68 public Component getChildAt(int index) 69 { 70 return _children.get(index); 71 } 72 73 @Override 74 public void removeChild(Component child) 75 { 76 _children.remove(child); 77 } 78 79 @Override 80 public void doSomething() 81 { 82 System.out.println("容器对象处理了某个事务"); 83 } 84 } 85 86 /** 87 * 叶子类 88 */ 89 public static class Leaf extends Component 90 { 91 @Override 92 public void addChild(Component child) throws Exception 93 { 94 throw new Exception("叶子对象不能添加子对象"); 95 } 96 97 @Override 98 public Component getChildAt(int index) throws Exception 99 { 100 throw new Exception("叶子对象不能获取子对象"); 101 } 102 103 @Override 104 public void removeChild(Component child) throws Exception 105 { 106 throw new Exception("叶子对象不能移除子对象"); 107 } 108 109 @Override 110 public void doSomething() 111 { 112 System.out.println("叶子对象处理了某个事务"); 113 } 114 } 115 }