共计 2127 个字符,预计需要花费 6 分钟才能阅读完成。
将对象组合成树形结构以表示“部分 - 整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性。
组合模式(Composite)经常用于树形结构,为了简化代码,使用 Composite 可以把一个叶子节点与一个父节点统一起来处理。
我们来看一个具体的例子。在 XML 或 HTML 中,从根节点开始,每个节点都可能包含任意个其他节点,这些层层嵌套的节点就构成了一颗树。
要以树的结构表示 XML,我们可以先抽象出节点类型Node
:
public interface Node {// 添加一个节点为子节点:
Node add(Node node);
// 获取子节点:
List<Node> children();
// 输出为 XML:
String toXml();
}
对于一个 <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";
String end = "</" + name + ">\n";
StringJoiner sj = new StringJoiner("", start, end);
list.forEach(node -> {sj.add(node.toXml() + "\n");
});
return sj.toString();}
}
对于普通文本,我们把它看作TextNode
,它没有子节点:
public class TextNode implements Node {private String text;
public TextNode(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;
}
}
此外,还可以有注释节点:
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
,我们就可以构造出一颗树:
Node root = new ElementNode("school");
root.add(new ElementNode("classA")
.add(new TextNode("Tom"))
.add(new TextNode("Alice")));
root.add(new ElementNode("classB")
.add(new TextNode("Bob"))
.add(new TextNode("Grace"))
.add(new CommentNode("comment...")));
System.out.println(root.toXml());
最后通过 root
节点输出的 XML 如下:
<school>
<classA>
Tom
Alice
</classA>
<classB>
Bob
Grace
<!-- comment... -->
</classB>
</school>
可见,使用 Composite 模式时,需要先统一单个节点以及“容器”节点的接口:
┌───────────┐
│ Node │
└───────────┘
▲
┌────────────┼────────────┐
│ │ │
┌───────────┐┌───────────┐┌───────────┐
│ElementNode││ TextNode ││CommentNode│
└───────────┘└───────────┘└───────────┘
作为容器节点的 ElementNode
又可以添加任意个Node
,这样就可以构成层级结构。
类似的,像文件夹和文件、GUI 窗口的各种组件,都符合 Composite 模式的定义,因为它们的结构天生就是层级结构。
练习
使用 Composite 模式构造 XML。
下载练习
小结
Composite 模式使得叶子对象和容器对象具有一致性,从而形成统一的树形结构,并用一致的方式去处理它们。
正文完
星哥玩云-微信公众号