组合模式-Composite(Java实现)

组合模式-Composite

Composite模式使得用户对单个对象和组合对象的使用具有一致性.

以<<图解设计模式>>的文件例子来说: 文件夹是文件的组合, 文件是单个对象, 文件夹是多个文件的组合. 不过对用户来说, 无论是文件还是文件夹, 他希望使用一个统一的方法来管理他们.这就需要将他们再次抽象出来.

解读一下这个类图就明白了:

1. 文件是一个组件

2. 文件夹也是一个组件

3. 文件夹里有很多组件:

       3.1 文件夹里可以有文件

       3.2 文件夹里可以有文件夹

Component抽象类

这是文件 文件夹的抽象定义类--组件类

/**
 * 这里是文件/文件夹 的统一抽象类 "组件类"
 */
public abstract class Component {
    /**
     * parent是父组件的指针, 也就是本例子中的"父级目录"
     */
    protected Component parent;

    /**
     * 获取组件名字
     */
    public abstract String getName();

    /**
     * 获取组件的大小
     */
    public abstract int getSize();

    /**
     * @implNote 向一个组件中添加一个组件.
     * @implSpec 组合模式中的叶子(Leaf)节点不可以使用这个方法, 用例子说明的话:
     * 一个文件不可以添加一个文件或文件夹, 只能是文件夹来添加文件或文件夹
     */
    public Component add(Component entry) {
        throw new RuntimeException("不支持此类操作...");
    }

    public void printList() {
        printList("");
    }

    protected abstract void printList(String prefix);

    /**
     * 获取绝对路径
     */
    public String getFullName() {
        StringBuilder fullName = new StringBuilder();
        Component entry = this;
        do {
            fullName.insert(0, "/" + entry.getName());
            entry = entry.parent;
        } while (entry != null);
        return fullName.toString();
    }

    /**
     * 其中的getSize() 会被子类重写, 因为文件大小可以很容易知道, 但是文件夹大小需要递归计算
     */
    @Override
    public String toString() {
        return getName() + " (" + getSize() + ")";
    }
}

MyFile类

MyFile类在组合模式中是Leaf(叶子)节点, 因为他不会包含其他组件.

我们可以把组件模式想象成一颗树(绿色表示文件夹, 橙色表示文件):

组合模式的叶子节点指的是文件节点, 因为文件永远也不会有子节点.

而绿的c1节点虽然现在是叶子节点, 但是如果给c1文件夹添加了一个文件的话, 他就不再是叶子节点了.

组合模式里无法继续添加子节点的就被称作Leaf(叶子)

上面那个树, 等价于下图:

 

public class MyFile extends Component {
    private String name;
    private int size;

    public MyFile(String name, int size) {
        this.name = name;
        this.size = size;
    }

    @Override
    public String getName() {
        return this.name;
    }

    @Override
    public int getSize() {
        return this.size;
    }

    @Override
    protected void printList(String prefix) {
        System.out.println(prefix + "/" + this.toString());
    }
}

MyDirectory类

MyDirectory类作为一个文件夹, 可以包含其他组件(文件/文件夹)

public class MyDirectory extends Component {

    private String name;
    private ArrayList<Component> substance = new ArrayList<>();

    public MyDirectory(String name) {
        this.name = name;
    }

    @Override
    public String getName() {
        return this.name;
    }

    /**
     * 获取文件夹的大小:
     * 1. size一开始是0
     * 2. 如果是文件, 那么直接把文件的大小加到size上
     * 3. 如果是文件夹, 那么就递归地查出该文件夹的大小, 然后加到size上.
     */
    @Override
    public int getSize() {
        int size = 0;
        for (Component entry : substance) {
            size += entry.getSize();
        }
        return size;
    }

    /**
     * 像一个文件夹中添加一个文件或文件夹
     */
    @Override
    public Component add(Component entry) {
        substance.add(entry);
        entry.parent = this;
        return this;
    }

    /**
     * 1. 打印当前目录的路径
     * 2. 然后打印出子目录, 子文件的路径
     * 3. 子目录再打印子子目录/子子文件的路径...如此递归
     */
    @Override
    protected void printList(String prefix) {
        System.out.println(prefix + "/" + this.toString());
        for (Component entry : substance) {
            entry.printList(prefix + "/" + name);
        }
    }
}

  

Main

用于测试运行

public class Main {
    public static void main(String[] args) {

        /* 本例子目录结构如下:
          一级目录   二级目录   三级目录
            a1
            |-------b1
            |-------b2
            |
            a2
            |-------c1
                    |-------Composite.java
                    |-------king.python

            |-------c2
         */

        MyDirectory a1 = new MyDirectory("a1");
        MyDirectory a2 = new MyDirectory("a2");

        MyDirectory b1 = new MyDirectory("b1");
        MyDirectory b2 = new MyDirectory("b2");
        a1.add(b1).add(b2);

        MyDirectory c1 = new MyDirectory("c1");
        MyDirectory c2 = new MyDirectory("c2");
        a2.add(c1).add(c2);

        MyFile java = new MyFile("Composite.java", 100);
        MyFile python = new MyFile("king.python", 214);
        c1.add(java).add(python);

        /*-****** getFullName() ************-*/
        System.out.println(java.getFullName());
        System.out.println(python.getFullName());
        System.out.println("");
        /*-****** getFullName() ************-*/
        a1.printList();
        System.out.println("-----");
        a2.printList();
    }
}

猜你喜欢

转载自www.cnblogs.com/noKing/p/9020119.html