组合模式(Composite)经常用于树形结构,为了简化代码,使用Composite可以把一个叶子节点与一个父节点统一起来处理。
我们来看一个具体的例子。在XML或HTML中,从根节点开始,每个节点都可能包含任意个其他节点,这些层层嵌套的节点就构成了一颗树。
要以树的结构表示XML,我们可以先抽象出节点类型:
对于一个<abc>
这样的节点,我们称之为ElementNode
,它可以作为容器包含多个子节点:
public class ElementNode implements Node {
private String name;
private List<Node> list = new ArrayList<>();
public ElementNode(String name) {
this.name = name;
}
public Node add(Node node) {
list.add(node);
return this;
}
public List<Node> children() {
return list;
}
public String toXml() {
String start = "<" + name + ">\n";
StringJoiner sj = new StringJoiner("", start, end);
list.forEach(node -> {
sj.add(node.toXml() + "\n");
});
return sj.toString();
}
}
此外,还可以有注释节点:
public class CommentNode implements Node {
private String text;
public CommentNode(String text) {
this.text = text;
}
public Node add(Node node) {
throw new UnsupportedOperationException();
public List<Node> children() {
return List.of();
public String toXml() {
return "<!-- " + text + " -->";
}
}
通过ElementNode
、TextNode
和CommentNode
,我们就可以构造出一颗树:
最后通过root
节点输出的XML如下:
<school>
<classA>
Tom
Alice
</classA>
<classB>
Bob
Grace
<!-- comment... -->
</classB>
可见,使用Composite模式时,需要先统一单个节点以及“容器”节点的接口:
类似的,像文件夹和文件、GUI窗口的各种组件,都符合Composite模式的定义,因为它们的结构天生就是层级结构。
从下载练习:使用Composite模式构造XML (推荐使用快速下载)
Composite模式使得叶子对象和容器对象具有一致性,从而形成统一的树形结构,并用一致的方式去处理它们。