Composite 设计模式?

在计算机的文件系统中,有“文件夹”的概念(在有些操作系统(Linux操作系统)中,也称为“目录”)。文件夹里面既可以放入文件,也可以放入其他文件夹(子文件夹)。在子文件夹中,一样地既可以放入文件,也可以放入子文件夹。可以说,文件夹是形成了一种容器结构、递归结构。

  • 结构模式:能够使容器与内容具有一致性,创造出递归结构的模式就是Composite模式。
  • 关注点:使用Composite模式可以使容器与内容具有一致性,也可以称其为多个和单个的一致性,即将多个对象结合在一起,当作一个对象进行处理。

理清职责

  • 到处存在的递归结构:
  1. 在视窗系统中,一个窗口可以含有一个子窗口,
    2.在文章的列表中,各列表之间可以相互嵌套,这也是一种递归结构。
    3.将多条计算机命令合并为一条宏命令时,如果使用递归结构实现宏命。
    4.树结构的数据结构都适用Composite模式。
  • 实现:演示文件夹 文件子项之间的层次关系
    名字===================>>>说明
    Entry || 抽象类,用来实现File类和Directory类的一致性
    File || 表示文件的类
    Directory || 表示文件夹的类
    FileTreatementException || 表示向文件中增加Entry时发生的异常的类
    Main || 测试程序行为的类
  • Add()方法的存在位置:
  1. 存在Entry 抛出异常。
  2. 存在Entry 中什么也不做。
  3. 声明在Entry中为抽象方法 不去实现。
  4. 直接定义在Directory类中,但是需要关注类型之间的转换。

UML

Composite模式(组合设计模式)_ide

类图:

Composite模式(组合设计模式)_抽象方法_02

Code

  • Entry

···

public abstract class Entry {

/**
* 1. 文件名
* 2. 文件大小
* @return
*/
public abstract String getName();
public abstract int getSize();

/**
* Directory 增加条目
* File 不能增加条目
*/
public Entry add(Entry entry)throws FileTreatementException{
throw new FileTreatementException();
}

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

protected abstract void printList(String prefix);

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

}

···

  • 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);
}
}

  • Directory

public class Directory extends Entry {

private String name;

private List<Entry> directory=new ArrayList<>();

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

@Override
public Entry add(Entry entry) throws FileTreatementException {
directory.add(entry);
return this;
}

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

/**
* getSize() | printList(String prefix)
*
* 都会递归去遍历下面可能存在的 目录或者文件的子项
*/

@Override
public int getSize() {
int size=0;
Iterator<Entry> it = directory.iterator();
while (it.hasNext()){
// 这里的Entry 可能是目录 也可能是文件
Entry next = it.next();
size+=next.getSize();
}

return size;
}

@Override
protected void printList(String prefix) {
// 这里的 prefix是一个引用 this将会调用tostring()方法 又会继续调用getName() getSize()方法
System.out.println(prefix+"/"+this);
Iterator<Entry> it = directory.iterator();
while(it.hasNext()){
// 这里的Entry 可能是目录 也可能是文件
Entry next = it.next();
next.printList(prefix+"/"+this);
}
}
}


  • FileTreatementException

public class FileTreatementException extends Exception {

public FileTreatementException() {
}

public FileTreatementException(String message) {
super(message);
}
}

  • 定义的目的结构:
start +++++++++++
/root(16000)
/root(16000)/bin(16000)
/root(16000)/bin(16000)/vi(1000)
/root(16000)/bin(16000)/notepaid(15000)
/root(16000)/temp(0)
/root(16000)/user(0)
  • MainT
public class MainT {

public static void main(String[] args) throws FileTreatementException{

System.out.println("start +++++++++++");

Directory rootdir=new Directory("root");

Directory bindir = new Directory("bin");
Directory tempdir = new Directory("temp");
Directory userdir = new Directory("user");

rootdir.add(bindir);
rootdir.add(tempdir);
rootdir.add(userdir);

bindir.add(new File("vi",1000));
bindir.add(new File("notepaid",15000));

rootdir.printList();
}
}