组合模式(Composite)经常用于树形结构,为了简化代码,使用Composite可以把一个叶子节点与一个父节点统一起来处理。

    我们来看一个具体的例子。在XML或HTML中,从根节点开始,每个节点都可能包含任意个其他节点,这些层层嵌套的节点就构成了一颗树。

    要以树的结构表示XML,我们可以先抽象出节点类型:

    对于一个<abc>这样的节点,我们称之为ElementNode,它可以作为容器包含多个子节点:

    1. public class ElementNode implements Node {
    2. private String name;
    3. private List<Node> list = new ArrayList<>();
    4. public ElementNode(String name) {
    5. this.name = name;
    6. }
    7. public Node add(Node node) {
    8. list.add(node);
    9. return this;
    10. }
    11. public List<Node> children() {
    12. return list;
    13. }
    14. public String toXml() {
    15. String start = "<" + name + ">\n";
    16. StringJoiner sj = new StringJoiner("", start, end);
    17. list.forEach(node -> {
    18. sj.add(node.toXml() + "\n");
    19. });
    20. return sj.toString();
    21. }
    22. }

    此外,还可以有注释节点:

    1. public class CommentNode implements Node {
    2. private String text;
    3. public CommentNode(String text) {
    4. this.text = text;
    5. }
    6. public Node add(Node node) {
    7. throw new UnsupportedOperationException();
    8. public List<Node> children() {
    9. return List.of();
    10. public String toXml() {
    11. return "<!-- " + text + " -->";
    12. }
    13. }

    通过ElementNodeTextNodeCommentNode,我们就可以构造出一颗树:

    最后通过root节点输出的XML如下:

    1. <school>
    2. <classA>
    3. Tom
    4. Alice
    5. </classA>
    6. <classB>
    7. Bob
    8. Grace
    9. <!-- comment... -->
    10. </classB>

    可见,使用Composite模式时,需要先统一单个节点以及“容器”节点的接口:

    类似的,像文件夹和文件、GUI窗口的各种组件,都符合Composite模式的定义,因为它们的结构天生就是层级结构。

    从下载练习:使用Composite模式构造XML (推荐使用快速下载)

    Composite模式使得叶子对象和容器对象具有一致性,从而形成统一的树形结构,并用一致的方式去处理它们。

    组合 - 图1