组合模式 一、组合模式是什么? Compose objects into tree structure to represent part-whole hierarchies.Composite lets client treat individual objects and compositions of objects uniformly.
组合模式(Composite Design Pattern):将一组对象组织成树形结构,以表示一种“部分 - 整体”的层次结构。
也可以这么说,组合模式就是把容器与内容看成同一种对象,并将它们组合成树状结构,创造一种递归的形式。
比如文件和目录,虽然直观上是不同的对象,但是如果使用组合模式来实现它们的话,可以将文件和目录都看成是继承于同一种条目类,因此算是属于同一类对象。
其次,目录中又可以继续放文件和目录,形成了递归,最终是一种树状的层次结构。
二、为什么要用组合模式? 组合模式使用的场景有限,对数据格式比较严格:
尽管场景少,但是数据满足递归结构时,组合模式还是能发挥比较大的作用的:
组合模式可以让客户端以统一的方式访问数据节点,因为它们是同一种对象
三、组合模式的结构是怎么样的? 组合模式包含的角色有以下几个:
抽象组件(Component):为树叶组件和复合组件提供一致性的抽象接口,并实现它们的默认行为
树叶组件(Leaf):表示内容,不能再放其他抽象组件对象,在结构中属于最小对象
复合组件(Composite):表示容器,可以放入其他抽象组件对象,包括树叶组件和复合组件
示例程序结构:
抽象组件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 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) ; @Override public String toString () { return getName() + " (" + getSize() + ")" ; } }
树叶组件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 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 ); } }
复合组件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 public class Directory extends Entry { private String name; private List<Entry> directory = new ArrayList <>(); public Directory (String name) { this .name = name; } @Override public String getName () { return name; } @Override public int getSize () { int size = 0 ; for (Entry entry : directory) { size += entry.getSize(); } return size; } @Override public Entry add (Entry entry) throws FileTreatmentException { directory.add(entry); return this ; } @Override protected void printList (String prefix) { System.out.println(prefix + "/" + this ); for (Entry entry : directory) { entry.printList(prefix + "/" + name); } } }
客户端调用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public class MainTest { public static void main (String[] args) { 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 user 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 )); yuki.add(new File ("Composite.java" , 300 )); hanako.add(new File ("memo.text" , 400 )); tomura.add(new File ("game.doc" , 500 )); tomura.add(new File ("junk.maik" , 600 )); rootDir.printList(); } }
四、组合模式有什么优缺点? 优点:
可以统一地对待内容组件和复合组件,使用简单
添加新的组件,不会影响客户端调用,满足“开闭原则”
缺点: