实现容器与内容的一致性-Composite模式

135 阅读2分钟

1、引入

Composite,译为复合物。乍一听复合物模式似乎有点云里雾里,不妨从以下角度来理解:

以操作系统中的文件夹为例,文件夹中存在着许多文件,包括但不限于:文件夹,文本文档,快捷方式等。这些文件种类繁多,一同组成了复合物(文件夹,容器)。而能够存进文件夹中的,虽然多种多样,但是它们都是文件(内容,存在共通性)。

而Composite模式就是这样的一种模式:能够在容器(复合物)中放入内容甚至更小的容器,更小的容器中又能放入内容和更更小的容器,形成一种递归结构。而能够实现这种结构,需要容器与内容具有一致性

2、示例

还是以上文的文件夹为例。

2.1、文件夹与文件的统一抽象父类Entry

共同的父类实现了文件夹与文件的统一

public abstract class Entry {
    public abstract String getName();

    public abstract int getSize();

    public Entry add(Entry entry)throws FileTreatMentException {
        throw new FileTreatMentException();
    }
    
    public void printList() {
        printList("");
    }

    protected abstract void printList(String prefix);

    public String toString() {
        return getName()+"("+getSize()+")";
    }
}

2.2、File类

public class File extends Entry{
    private String name;
    private int size;

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

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

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

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

2.3、Directory类

实现了文件夹的添加等功能

public class Directory extends Entry{
    private String name;
    private ArrayList<Entry> dir=new ArrayList<>();

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

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

    @Override
    public int getSize() {
        int size=0;
        Iterator<Entry> iterator = dir.iterator();
        while (iterator.hasNext()) {
            size+=iterator.next().getSize();
        }
        return size;
    }

    public Entry add(Entry entry) {
        dir.add(entry);
        return this;
    }

    @Override
    protected void printList(String prefix) {
        System.out.println(prefix+"/"+this);
        Iterator<Entry> iterator = dir.iterator();
        while (iterator.hasNext()) {
            iterator.next().printList(prefix+"/"+name);
        }
    }
}

2.4、测试

public class Main {
    public static void main(String[] args) {
        System.out.println("Making entries....");
        Directory root = new Directory("root");
        Directory bin = new Directory("bin");
        Directory tmp = new Directory("tmp");
        root.add(bin);
        root.add(tmp);

        bin.add(new File("vim", 1000));
        bin.add(new File("ls", 500));

        tmp.add(new File("mysql_log", 20000));
        tmp.add(new File("system_security_log)",100000));
        root.printList();
    }
}

运行结果:

image.png 可以看出,实现了文件夹逐级递归访问

3、tips

  • 这里Entry不使用接口原因是接口的修饰符固定为public,而被protected修饰的printList(String prefix)方法在接口中无法定义。
  • Composite模式除了在文件夹中有着应用,在视窗系统、文章列表、宏命令合成等存在递归机构的系统中也广泛应用。