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

猜你喜欢

转载自lizhao6210-126-com.iteye.com/blog/1762589
今日推荐