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())時,在編譯期不會有錯,但在執行期會報錯,這樣不容易被發覺錯誤出在哪。