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())时,在编译期不会有错,但在执行期会报错,这样不容易被发觉错误出在哪。