设计模式——组合模式(Composite)
Composite模式定义:
将对象以树形结构组织起来,以达成“部分-整体” 的层次结构,使得客户端对单个对象和组合对象的使用具有一致性。
Composite比较容易理解,想到Composite就应该想到树形结构图。组合体内这些对象都有共同接口,当组合体一个对象的方法被调用执行时,Composite将遍历(Iterator)整个树形结构,寻找同样包含这个方法的对象并实现调用执行。可以用牵一动百来形容。
Composite好处:
1.使客户端调用简单,客户端可以一致的使用组合结构或其中单个对象,用户就不必关心自己处理的是单个对象还是整个组合结构,这就简化了客户端代码。
2.更容易在组合体内加入对象部件,客户端不必因为加入了新的对象部件而更改代码。
如何使用Composite?
首先定义一个接口或抽象类,这是设计模式通用方式了,其他设计模式对接口内部定义限制不多,Composite却有个规定,那就是要在接口内部定义一个用于访问和管理Composite组合体的对象们(或称部件Component)。
Composite模式要对组合的对象进行管理,所以在一定位置给予对象的相关管理方法,如:add(),remove()等.Composite模式中对象的管理有两种方案。
1.安全方式:此方式只允许树枝构件有对象的管理方法。
2.透明方式:此方式只允许树枝和树叶都有对象的管理方法,但树叶对象中的管理方法无实际意义。
一.UML示意图
二.组成部分
抽象构件:抽象组合对象的公共行为接口
树叶构件:树叶对象,没有下级子对象
树枝构件:树枝对象,树枝对象可以包含一个或多个其他树枝或树叶对象
三.代码例子
1.抽象构件
package com.composite; public interface IFile { /** * 返回自己的实例 * @return */ public IFile getComposite(); /** * 获取名字 * @return */ public String getName(); /** * 设置名字 * @param name */ public void setName(String name); /** * 获取深度 * @return */ public int getDeep(); /** * 设置深度 * @param deep */ public void setDeep(int deep); }
2.叶子构件
package com.composite; public class File implements IFile{ /** * 文件名字 */ private String name; /** * 层级深度,根为0 */ private int deep; public File(String name) { this.name = name; } @Override public IFile getComposite() { return this; } @Override public String getName() { return name; } @Override public void setName(String name) { this.name = name; } @Override public int getDeep() { return deep; } @Override public void setDeep(int deep) { this.deep = deep; } }
3.树枝构件
package com.composite; import java.util.Vector; public class Folder implements IFile{ /** * 文件名字 */ private String name; /** * 层级深度,根为0 */ private int deep; /** * 直接子文件(夹)集合 */ private Vector<IFile> component = new Vector<IFile>(); public Folder(String name) { this.name = name; } @Override public IFile getComposite() { return this; } /** * 新增一个文件或文件夹 * @param file */ public void add(IFile file) { component.addElement(file); file.setDeep(this.deep+1); } /** * 删除一个文件或文件夹 * @param file */ public void remove(IFile file) { component.removeElement(file); } /** * 获取直接子文件(夹)集合 * @return */ public Vector<IFile> getComponent() { return this.component; } @Override public String getName() { return name; } @Override public void setName(String name) { this.name = name; } @Override public int getDeep() { return deep; } @Override public void setDeep(int deep) { this.deep = deep; } }
4.测试
package com.composite; import java.util.Iterator; import java.util.Vector; public class Test { public static void main(String[] args) { Folder root = new Folder("根节点"); Folder folder1_1 = new Folder("1_分支1"); Folder folder1_2 = new Folder("1_分支2"); File f1_1 = new File("1_叶1"); File f1_2 = new File("1_叶2"); File f1_3 = new File("1_叶3"); Folder folder2_1 = new Folder("2_分支1"); Folder folder2_2 = new Folder("2_分支2"); File f2_1 = new File("2_叶1"); File f2_2 = new File("2_叶2"); root.add(folder1_1); root.add(folder1_2); root.add(f1_1); root.add(f1_2); root.add(f1_3); folder1_2.add(folder2_1); folder1_2.add(folder2_2); folder1_2.add(f2_1); folder2_2.add(f2_2); outTree(root); } public static void outTree(Folder folder) { System.out.println(folder.getName()); iterateTree(folder); } public static void iterateTree(Folder folder) { Vector<IFile> clist = folder.getComponent(); for(Iterator<IFile> it = clist.iterator();it.hasNext();) { IFile em = it.next(); if(em instanceof Folder) { Folder cm = (Folder) em; System.out.println(getIndents(em.getDeep())+cm.getName()); iterateTree(cm); }else { System.out.println(getIndents(em.getDeep())+((File)em).getName()); } } } public static String getIndents(int x) { StringBuffer sb = new StringBuffer(); for(int i=0;i<x;i++) { sb.append("\t"); } return sb.toString(); } }
5.结果
四.总结
组合模式是对象的结构模式。在以后的项目中,如果遇到对象组合的情况,即也符合树结构的。可以考虑下此模式。此模式中讲述了安全方式和透明方式。
安全方式:抽象构件上只提供树叶和树枝公共的方法,没提供树枝独有的管理等方法(add(),remove())。这样的好处是安全,用户不会在树叶上使用add()等管理方法,缺点是不够透明,用户必须知识当前对象为树叶还是树枝(向下转型)。
透明方式:抽象构件上提供了满足树枝的所有方法(包括add(),remove()),这样做的好处是,用户可以任意执行对象的add()和remove()管理对象。缺点是如果用户在树叶上执行管理方式(add(),remove())时,在编译期不会有错,但在执行期会报错,这样不容易被发觉错误出在哪。