组合模式
概叙
在计算机文件系统中,文件夹既可以放文件,也可以放文件夹(子文件夹)。在子文件夹中,一样既可以放文件,也可以放子文件夹。可以说,文件夹形成了一种容器结构、递归结构。
虽然文件和文件夹是不同类型,但是都可以被放入文件夹中,。文件和文件夹有时也被统称为“目录条目”。在目录条目中,文件夹和文件被当作同一种对象看待(即一致性)。
将文件夹和文件都当作目录条目看待,将容器和内容作为同一种东西看待,可以帮助我们方便的处理问题。在容器中既可以放入内容,也可以放入小容器,在小容器中,又可以放入更小的容器。。。。。这样,就形成了容器结构、递归结构。
Composite模式就是用于创造这种结构的模式。能够时容器与内容具有一致性,创造递归结构。
示例程序
类的一览表
Entity抽象类,用来实现File和Directory的一致性File表示文件的类Directory表示文件夹的类Main测试入口
类图
代码
Entry类
抽象父类,File和Directory是其子类。
通过getName()获取名字,getSize()获取大小。
add()方法是向文件夹中放入文件(此处抛出异常,Directory需要将其覆盖)。
printList()为外部调用,printList(String prefix)为子类调用。
public abstract class Entity { public abstract String getName(); //获取名字 public abstract int getSize(); //获取大小 public Entity add(Entity entity) throws Exception { throw new RuntimeException("运行异常"); //加入目录条目 } public void printList() { printList(""); //显示目录条目一览 } protected abstract void printList(String prefix); //为一览加上前缀 @Override public String toString() { //显示代表类文字 return getName() + "(" + getSize() + ")"; } }
File类
name表示文件名,size表示文件大小。
实现printList(String prefix) 方法。
public class File extends Entity { 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类
表示文件夹的类,是Entity的子类。
name表示文件夹名,directory保存文件夹的目录条目(指定泛型Entity)。
getSize(),通过计算得出大小。size += entity.getSize()。entity不论是File的实例还是Directory的实例,我们都可以通过getSize得到它的大小。 这就是Composite模式的特征——“容器与内容的一致性”。
如果entity是Directory的实例,调用getSize()会将该文件夹下的所有目录条目大小加起来。如果还有子文件夹,又会调用getSize()方法,形成递归调用。getSize()方法的递归调用与Composite模式的结构是相对应的。
add方法用于向文件夹中加入子文件夹或文件。
public class Directory extends Entity { private String name; private ArrayList<Entity> directory = new ArrayList(); public Directory(String name) { this.name = name; } @Override public String getName() { return name; } @Override public int getSize() { int size = 0; Iterator<Entity> it = directory.iterator(); while (it.hasNext()) { Entity entity = it.next(); size += entity.getSize(); } return size; } @Override public Entity add(Entity entity) throws Exception { directory.add(entity); return this; } @Override protected void printList(String prefix) { System.out.println(prefix + "/" + this); Iterator<Entity> it = directory.iterator(); while (it.hasNext()) { Entity entity = it.next(); entity.printList(prefix + "/" + name); } } }
Main类
public class Main { public static void main(String[] args) { try { System.out.println("making root entries......"); Directory rootDir = new Directory("root"); Directory binDir = new Directory("bin"); Directory tmpDir = new Directory("tmp"); Directory usrDir = new Directory("usr"); rootDir.add(binDir); rootDir.add(tmpDir); rootDir.add(usrDir); binDir.add(new File("vi", 10000)); binDir.add(new File("latex", 20000)); rootDir.printList(); System.out.println(""); System.out.println("making usr entries......"); Directory yuki = new Directory("yuki"); Directory hanako = new Directory("hanako"); Directory tomura = new Directory("tomura"); usrDir.add(yuki); usrDir.add(hanako); usrDir.add(tomura); yuki.add(new File("diary.html", 100)); hanako.add(new File("memo.txt", 200)); tomura.add(new File("game.doc", 300)); tomura.add(new File("junk.mail", 500)); rootDir.printList(); } catch (Exception e) { e.printStackTrace(); } } } making root entries...... /root(30000) /root/bin(30000) /root/bin/vi(10000) /root/bin/latex(20000) /root/tmp(0) /root/usr(0) making usr entries...... /root(31100) /root/bin(30000) /root/bin/vi(10000) /root/bin/latex(20000) /root/tmp(0) /root/usr(1100) /root/usr/yuki(100) /root/usr/yuki/diary.html(100) /root/usr/hanako(200) /root/usr/hanako/memo.txt(200) /root/usr/tomura(800) /root/usr/tomura/game.doc(300) /root/usr/tomura/junk.mail(500)
登场角色
- Leaf(树叶)
- 表示内容角色,不能放入其他物品。(File)
- Composite(复合物)
- 表示容器角色,可以放入容器和树叶。(Directory)
- Component
- 使leaf与Composite具有一致性,是其父类(Entity)
- client
- 使用角色,(Main)
拓展
多个和单个的一致性
Composite模式可以使容器与内容具有一致性,也可称其为,多个和单个一致性,即将多个对象结合在一起,当作一个对象下使用。
add方法
- 定义在Entity中,默认报错
- 能够使用add方法的只有Directory
- 定义在Entity中,什么也不做
- 声明但不实现
- 声明抽象方法,子类实现。(这样的话File类中也必须定义完全没有用add方法)
- 定义在Directory中