天天看點

設計模式——組合模式(Composite)

Composite模式定義:

    将對象以樹形結構組織起來,以達成“部分-整體” 的層次結構,使得用戶端對單個對象群組合對象的使用具有一緻性。

    Composite比較容易了解,想到Composite就應該想到樹形結構圖。組合體内這些對象都有共同接口,當組合體一個對象的方法被調用執行時,Composite将周遊(Iterator)整個樹形結構,尋找同樣包含這個方法的對象并實作調用執行。可以用牽一動百來形容。

Composite好處:

    1.使用戶端調用簡單,用戶端可以一緻的使用組合結構或其中單個對象,使用者就不必關心自己處理的是單個對象還是整個組合結構,這就簡化了用戶端代碼。

    2.更容易在組合體内加入對象部件,用戶端不必因為加入了新的對象部件而更改代碼。

如何使用Composite?

    首先定義一個接口或抽象類,這是設計模式通用方式了,其他設計模式對接口内部定義限制不多,Composite卻有個規定,那就是要在接口内部定義一個用于通路和管理Composite組合體的對象們(或稱部件Component)。

    Composite模式要對組合的對象進行管理,是以在一定位置給予對象的相關管理方法,如:add(),remove()等.Composite模式中對象的管理有兩種方案。

    1.安全方式:此方式隻允許樹枝構件有對象的管理方法。

    2.透明方式:此方式隻允許樹枝和樹葉都有對象的管理方法,但樹葉對象中的管理方法無實際意義。

一.UML示意圖

設計模式——組合模式(Composite)

 二.組成部分

    抽象構件:抽象組合對象的公共行為接口

    樹葉構件:樹葉對象,沒有下級子對象

    樹枝構件:樹枝對象,樹枝對象可以包含一個或多個其他樹枝或樹葉對象

三.代碼例子

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.結果

設計模式——組合模式(Composite)

四.總結

    組合模式是對象的結構模式。在以後的項目中,如果遇到對象組合的情況,即也符合樹結構的。可以考慮下此模式。此模式中講述了安全方式和透明方式。

    安全方式:抽象構件上隻提供樹葉和樹枝公共的方法,沒提供樹枝獨有的管理等方法(add(),remove())。這樣的好處是安全,使用者不會在樹葉上使用add()等管理方法,缺點是不夠透明,使用者必須知識目前對象為樹葉還是樹枝(向下轉型)。

    透明方式:抽象構件上提供了滿足樹枝的所有方法(包括add(),remove()),這樣做的好處是,使用者可以任意執行對象的add()和remove()管理對象。缺點是如果使用者在樹葉上執行管理方式(add(),remove())時,在編譯期不會有錯,但在執行期會報錯,這樣不容易被發覺錯誤出在哪。

繼續閱讀