组合模式(composite pattern)

定义

允许你将对象组合成树形结构来表现整体/部分层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。

特点

1.结构为树形;
2.节点常见的方法有add()、remove()、getChild()等。

适用范围

树形结构的文件管理。

一般写法

我们来实现如下一棵树:


tree.png

首先先定义组件抽象类,如下所示:

/**
 * 定义组件抽象类,叶节点和组合节点都是组件类的子类,
 * 为方法提供默认实现,避免一些组件如叶子节点实现不必要的方法,
 * 这里自定义doSomething()实现要对组件的操作
 */
public abstract class Component {
    public void add(Component component) {
        throw new UnsupportedOperationException();
    }

    public void remove(Component component) {
        throw new UnsupportedOperationException();
    }

    public Component getChild(int i) {
        throw new UnsupportedOperationException();
    }

    public void doSomething() {
        throw new UnsupportedOperationException();
    }
}

接着具体节点继承组件抽象类:

import java.util.ArrayList;
import java.util.Iterator;

public class Node extends Component {
    // 用于保存节点下面的子节点
    ArrayList components = new ArrayList<>();

    // 定义节点ID
    int nodeId;

    // 构造器传入节点ID
    public Node(int nodeId) {
        this.nodeId = nodeId;
    }

    @Override
    public void add(Component component) {
        components.add(component);
    }

    @Override
    public void remove(Component component) {
        components.remove(component);
    }

    @Override
    public Component getChild(int i) {
        // 返回该节点下第i个子节点
        return components.get(i);
    }

    @Override
    public void doSomething() {
        // 先打印本节点ID
        System.out.println(nodeId);

        // 接着这里用迭代器模式打印子节点ID
        Iterator iterator = components.iterator();
        while (iterator.hasNext()) {
            Component component = (Component) iterator.next();

            // 递归调用,如果节点下面还有节点,会开始另一个节点的打印
            component.doSomething();
        }
    }
}

最后,节点之间的连接在后面的测试里进行。

组件模式测试

public class Main {
    public static void main(String[] args) {
        // 创建6个节点的树
        final int NODE_NUM = 6;
        Component[] nodes = new Component[NODE_NUM];
        for (int i = 0; i < NODE_NUM; i++) {
            nodes[i] = new Node(i);
        }

        // 节点组合连接
        nodes[0].add(nodes[1]);
        nodes[0].add(nodes[2]);
        nodes[0].add(nodes[3]);
        nodes[2].add(nodes[4]);
        nodes[2].add(nodes[5]);

        // 因为在doSomething()中是先打印节点ID,所以这里显示的结果
        // 是先序遍历打印,以0为根的树的先序顺序:根 - 左 - 右,
        //
        // 如果把节点打印,放在doSomeThing()最后打印,
        // 则为后序顺序遍历:左 - 右 - 根。
        nodes[0].doSomething();

        // nodes[0]的子节点有三个,其中索引为1的子节点就是nodes[2]
        System.out.println(nodes[0].getChild(1).equals(nodes[2]));

        // nodes[2]的子节点有两个,移除nodes[4],剩下nodes[5]
        nodes[2].remove(nodes[4]);
        nodes[2].doSomething();
    }
}

测试结果

0
1
2
4
5
3
true
2
5

你可能感兴趣的:(组合模式(composite pattern))