Java设计模式之结构型模式-组合模式(Composite)

组合模式: 将对象组合成树形结构以表示”部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

适用范围

  1. 需求中体现部分与整体层次的结构
  2. 希望用户能够忽略组合对象与单个对象的差异,统一地使用组合结构中的所有对象

三个要素

  1. Component: 作为组合中的对象声明的接口,在适当的情况下,实现所有类公有接口的默认行为。声明一个接口用于访问和管理Component的子组件。
  2. Leaf: 作为组合中叶节点对象,叶节点没有子节点。在组合当中定义节点对象的行为。
  3. Composite: 定义拥有子部件的部件的行为,存储子部件。在Component接口当中实现和子部件有关的操作。

实现过程

  我下面以这个二叉树为例子(画的比较丑,多担待),节点中包含节点的名称和节点的等级。
  Java设计模式之结构型模式-组合模式(Composite)_第1张图片
  我们知道二叉树大致可分为叶子节点和非叶子节点(树枝节点),非叶子节点同时又可以拥有非叶子节点和叶子节点,而叶子节点作为末端结点则不能。
  究其源由,我们可以将这两者抽象成节点类作为我们的Component。并在其内部定义一些默认行为用来访问和操作子节点。

public abstract class Node {

    private String name;

    private String level;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getLevel() {
        return level;
    }

    public void setLevel(String level) {
        this.level = level;
    }

    public Node(String name, String level) {
        super();
        this.name = name;
        this.level = level;
    }

    public abstract void addNode(Node node);

    public abstract void removeNode(Node node);

    public abstract void show();
}

  下面来看看叶子节点Leaf的实现方式:

public class LeafNode extends Node {

    public LeafNode(String name, String level) {
        super(name, level);
    }

    @Override
    public void addNode(Node node) {
        System.out.println("叶子节点不能增加子节点...");
    }

    @Override
    public void removeNode(Node node) {
        System.out.println("叶子节点没有子节点, 不能够删除...");
    }

    @Override
    public void show() {
        System.out.println(getLevel() + " : " + getName());
    }

}

  再来看看树枝节点Composite的实现方式:

public class BranchNode extends Node {

    private List nodes = null;

    public BranchNode(String name, String level) {
        super(name, level);
        nodes = new ArrayList<>();
    }

    public List getNodes() {
        return nodes;
    }

    public void setNodes(List nodes) {
        this.nodes = nodes;
    }

    @Override
    public void addNode(Node node) {
        nodes.add(node);
    }

    @Override
    public void removeNode(Node node) {
        nodes.remove(node);
    }

    @Override
    public void show() {
        System.out.println(getLevel() + " : " + getName());
        for (Node node : nodes) {
            node.show();
        }
    }

}

  从叶子节点和树枝节点两者代码的比较中,我们可以发现,叶子节点和树枝节点两者所具备的接口是一致的。但是对于叶子节点来说实现addNode()和removeNode()这两个方法是没有什么意义的,因为叶子节点不存在子节点。但是这么做又有一个好处,就是这样能够消除叶子节点与树枝节点在抽象层次上的差异。
  树枝节点和叶子节点两者的主要差异在于其各自的具体实现类当中,树枝节点比叶子节点多拥有 nodes 这个集合类型的属性,可以用来存放其他的下属树枝节点和叶子节点。
  实现类的show()方法主要起到了递归循环显示所有下级节点的作用。
  写个测试类测试下上述二叉树组合的过程:

public class ComponentTest {
    public static void main(String[] args) {
        BranchNode root = new BranchNode("Node A", "1");
        BranchNode branchNodeB = new BranchNode("Node B", "1-1");
        BranchNode branchNodeC = new BranchNode("Node C", "1-2");

        branchNodeB.getNodes().add(new LeafNode("Node D", "1-1-1"));
        branchNodeB.getNodes().add(new LeafNode("Node E", "1-1-2"));
        branchNodeC.getNodes().add(new LeafNode("Node F", "1-2-1"));
        branchNodeC.getNodes().add(new LeafNode("Node G", "1-2-2"));

        root.addNode(branchNodeB);
        root.addNode(branchNodeC);

        root.show();
    }
}

运行结果如下所示:

1 : Node A
1-1 : Node B
1-1-1 : Node D
1-1-2 : Node E
1-2 : Node C
1-2-1 : Node F
1-2-2 : Node G

透明方式和安全方式的区别

  组合模式有透明和安全两种方式。关于透明方式其实在上文中已经提到过,只是我没有具体指明,那在这里再叙述一下。

透明方式

  之前在例子中讲到,我们的叶子节点不存在子节点却也实现了addNode()和removeNode()这两个方法,虽然没有什么意义,但是这样做却统一了这两者的行为接口,消除了两者在抽象层次上的差异。

安全方式

  安全方式自然和透明方式相反。即叶子节点和树枝节点这两者的行为接口不相同。那么就不用在抽象接口中定义默认行为接口。只需要在树枝节点的具体实现类中声明一系列方法来管理子节点即可。

你可能感兴趣的:(设计模式)