Java设计模式(十七)—— 组合模式

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

适用组合模式的情景如下:

  • 希望表示对象的“部分—整体”层次结构
  • 希望用户用一致方式处理个体和组合对象

一、问题的提出

我们研究的问题有许多树形结构的问题,例如文件结构:

Java设计模式(十七)—— 组合模式_第1张图片

 例如,要用程序创建文件结构,为了验证正确与否,还要再控制台上输出从某目录开始的所有文件信息。文件树形结构可以分为两类,一类是文件叶子节点,无后继节点,一类是中间目录节点,有后继节点。具体代码如下:

(1)文件节点类

public class FileLeaf {
    String fileName;

    public FileLeaf(String fileName) {
        this.fileName = fileName;
    }
    public void display() {
        System.out.println(fileName);
    }
}

(2)中间目录节点类 DirectNode

public class DirectNode {
    String nodeName;

    public DirectNode(String nodeName) {
        this.nodeName = nodeName;
    }
    //后继目录集合
    ArrayList nodeList = new ArrayList<>();
    //当前目录文件集合
    ArrayList fileList = new ArrayList<>();
    //添加下一级子目录
    public void addNode(DirectNode node ) {
        nodeList.add(node);
    }
    //添加本级文件
    public void addLeaf(FileLeaf leaf) {
        fileList.add(leaf);
    }
    //从本级目录开始显示
    public void display() {
        for (int i = 0; i < fileList.size(); i++) {
            fileList.get(i).display();
        }
        for (int i = 0; i < nodeList.size(); i++) {
            System.out.println(nodeList.get(i).nodeName);
            nodeList.get(i).display();
        }
    }
}

(3)测试类

public class Test {
    public static void createTree(DirectNode node) {
        File f = new File(node.nodeName);
        File f2[] = f.listFiles();
        for (int i = 0; i < f2.length; i++) {
            //如果是文件类型,则把他添加到当前目录文件集合
            if (f2[i].isFile()) {
                FileLeaf l = new FileLeaf(f2[i].getAbsolutePath());
                node.addLeaf(l);
            }
            //如果是目录类型,则把他添加到目录集合,然后继续递归添加
            if (f2[i].isDirectory()) {
                DirectNode node2 = new DirectNode(f2[i].getAbsolutePath());
                node.addNode(node2);
                createTree(node2);
            }
        }
    }

    public static void main(String[] args) {
        DirectNode start = new DirectNode("D:\\学习笔记\\Linux\\docker-book-master\\docker");
        createTree(start);
        start.display();
    }
}

二、组合模式

        从上面图片可知:根目录是由两个子目录组成的;第一个子目录由两个文件组成;第二个子目录也由两个文件组成,因此树形形式也可以叫做组合模式。

        在图中,把节点分为叶子节点与目录节点,它们是孤立的。然后把叶子节点与目录节点都看成相同性质的节点,只不过目录节点的后继节点不为空,而叶子节点的后继节点为null。这样就能够对树形结构的所有节点执行相同的操作,这也是组合模式最大的特点。

采用组合模式修改上面例子的功能:

(1)定义抽象节点类Node

该类是叶子节点与目录节点的父类,节点名称是name。其主要包括两类方法:一类方法是所有节点具有相同形式、不同内容的方法。这类方法要定义成抽象方法,如display();另一类方法是目录节点必须重写,而叶子节点不需要重写的方法,相当于为叶子节点提供了默认实现,如addNode()方法。因为叶子对象没有该功能,所以可以通过抛出异常防止叶子节点无效调用该方法。/

public abstract class Node {
    protected String name;
    public Node(String name) {
        this.name = name;
    }
    public void addNode(Node node) throws Exception {
        throw new Exception("无效的异常");
    }
    abstract void display();
}

(2)文件叶子节点类 FileNode

public class FileNode extends Node{
    public FileNode(String name) {
        super(name);
    }
    @Override
    void display() {
        System.out.println(name);
    }
}

(3)目录节点类 DirectNode

        该类从Node抽象类派生后,与原DirectNode类相比,主要有以下不同:

  • 由定义两个结合类成员变量转为定义一个集合类成员变量nodeList
  • 由定义两个添加方法转为定义一个添加方法addNode()
  • display() 方法中,由两个不同元素的循环转为一个对相同性质节点Node循环。
public class DirectNode2 extends Node{
    private ArrayList nodeList = new ArrayList<>();
    public DirectNode2(String name) {
        super(name);
    }
    public void addNode(Node node) throws Exception {
        nodeList.add(node);
    }
    @Override
    void display() {
        System.out.println(name);
        for (int i = 0; i < nodeList.size(); i++) {
            nodeList.get(i).display();
        }
    }
}

(4) 测试类

public class Test2 {
    public static void createTree(Node node) throws Exception {
        File f = new File(node.name);
        File f2[] = f.listFiles();
        for (int i = 0; i < f2.length; i++) {
            if (f2[i].isFile()) {
                Node node2 = new FileNode(f2[i].getAbsolutePath());
                node.addNode(node2);
            }
            if (f2[i].isDirectory()) {
                Node node2 = new DirectNode2(f2[i].getAbsolutePath());
                node.addNode(node2);
                createTree(node2);
            }
        }
    }

    public static void main(String[] args) throws Exception {
        Node start = new DirectNode2("D:\\学习笔记\\Linux\\docker-book-master\\docker");
        createTree(start);
        start.display();
    }
}

你可能感兴趣的:(设计模式,java,组合模式,设计模式)