組合模式將對(duì)象組合成樹(shù)形結(jié)構(gòu)以表示“部分-整體”的層次結(jié)構(gòu)。C o m p o s i t e 使得用戶對(duì)單個(gè)對(duì)象和組合對(duì)象的使用具有一致性。
模式圖:
適用場(chǎng)景:
- 你想表示對(duì)象的部分-整體層次結(jié)構(gòu)。
- 你希望用戶忽略組合對(duì)象與單個(gè)對(duì)象的不同,用戶將統(tǒng)一地使用組合結(jié)構(gòu)中的所有對(duì)象。
舉例:
namespace FactoryMethod_DesignPattern{ using System; using System.Collections; abstract class Component { protected string strName; public Component(string name) { strName = name; } abstract public void Add(Component c); public abstract void DumpContents(); // other operations for delete, get, etc. } class Composite : Component { private ArrayList ComponentList = new ArrayList(); public Composite(string s) : base(s) {} override public void Add(Component c) { ComponentList.Add(c); } public override void DumpContents() { // First dump the name of this composite node Console.WriteLine("Node: {0}", strName); // Then loop through children, and get then to dump their contents foreach (Component c in ComponentList) { c.DumpContents(); } } } class Leaf : Component { public Leaf(string s) : base(s) {} override public void Add(Component c) { Console.WriteLine("Cannot add to a leaf"); } public override void DumpContents() { Console.WriteLine("Node: {0}", strName); } } /// <summary> /// Summary description for Client. /// </summary> public class Client { Component SetupTree() { // here we have to create a tree structure, // consisting of composites and leafs. Composite root = new Composite("root-composite"); Composite parentcomposite; Composite composite; Leaf leaf; parentcomposite = root; composite = new Composite("first level - first sibling - composite"); parentcomposite.Add(composite); leaf = new Leaf("first level - second sibling - leaf"); parentcomposite.Add(leaf); parentcomposite = composite; composite = new Composite("second level - first sibling - composite"); parentcomposite.Add(composite); composite = new Composite("second level - second sibling - composite"); parentcomposite.Add(composite); // we will leaf the second level - first sibling empty, and start // populating the second level - second sibling parentcomposite = composite; leaf = new Leaf("third level - first sibling - leaf"); parentcomposite.Add(leaf); leaf = new Leaf("third level - second sibling - leaf"); parentcomposite.Add(leaf); composite = new Composite("third level - third sibling - composite"); parentcomposite.Add(composite); return root; } public static int Main(string[] args) { Component component; Client c = new Client(); component = c.SetupTree(); component.DumpContents(); return 0; } }}
可以看出,Composite類(lèi)型的對(duì)象可以包含其它Component類(lèi)型的對(duì)象。換而言之,Composite類(lèi)型對(duì)象可以含有其它的樹(shù)枝(Composite)類(lèi)型或樹(shù)葉(Leaf)類(lèi)型的對(duì)象。
合成模式的實(shí)現(xiàn)根據(jù)所實(shí)現(xiàn)接口的區(qū)別分為兩種形式,分別稱為安全模式和透明模式。合成模式可以不提供父對(duì)象的管理方法,但合成模式必須在合適的地方提供子對(duì)象的管理方法(諸如:add、remove、getChild等)。
透明方式
作為第一種選擇,在Component里面聲明所有的用來(lái)管理子類(lèi)對(duì)象的方法,包括add()、remove(),以及getChild()方法。這樣做的好處是所有的構(gòu)件類(lèi)都有相同的接口。在客戶端看來(lái),樹(shù)葉類(lèi)對(duì)象與合成類(lèi)對(duì)象的區(qū)別起碼在接口層次上消失了,客戶端可以同等同的對(duì)待所有的對(duì)象。這就是透明形式的合成模式。
這個(gè)選擇的缺點(diǎn)是不夠安全,因?yàn)闃?shù)葉類(lèi)對(duì)象和合成類(lèi)對(duì)象在本質(zhì)上是有區(qū)別的。樹(shù)葉類(lèi)對(duì)象不可能有下一個(gè)層次的對(duì)象,因此add()、remove()以及getChild()方法沒(méi)有意義,是在編譯時(shí)期不會(huì)出錯(cuò),而只會(huì)在運(yùn)行時(shí)期才會(huì)出錯(cuò)。
安全方式
第二種選擇是在Composite類(lèi)里面聲明所有的用來(lái)管理子類(lèi)對(duì)象的方法。這樣的做法是安全的做法,因?yàn)闃?shù)葉類(lèi)型的對(duì)象根本就沒(méi)有管理子類(lèi)對(duì)象的方法,因此,如果客戶端對(duì)樹(shù)葉類(lèi)對(duì)象使用這些方法時(shí),程序會(huì)在編譯時(shí)期出錯(cuò)。
這個(gè)選擇的缺點(diǎn)是不夠透明,因?yàn)闃?shù)葉類(lèi)和合成類(lèi)將具有不同的接口。
這兩個(gè)形式各有優(yōu)缺點(diǎn),需要根據(jù)軟件的具體情況做出取舍決定。
安全式的合成模式實(shí)現(xiàn): 只有composite有Add ,remove,delete等方法.
以下示例性代碼演示了安全式的合成模式代碼:
// Composite pattern -- Structural example using System;using System.Text;using System.Collections;// "Component"abstract class Component{ // Fields protected string name; // Constructors public Component( string name ) { this.name = name; } // Operation public abstract void Display( int depth );}// "Composite"class Composite : Component{ // Fields private ArrayList children = new ArrayList(); // Constructors public Composite( string name ) : base( name ) {} // Methods public void Add( Component component ) { children.Add( component ); } public void Remove( Component component ) { children.Remove( component ); } public override void Display( int depth ) { Console.WriteLine( new String( '-', depth ) + name ); // Display each of the node's children foreach( Component component in children ) component.Display( depth + 2 ); }}// "Leaf"class Leaf : Component{ // Constructors public Leaf( string name ) : base( name ) {} // Methods public override void Display( int depth ) { Console.WriteLine( new String( '-', depth ) + name ); }}/// <summary>/// Client test/// </summary>public class Client{ public static void Main( string[] args ) { // Create a tree structure Composite root = new Composite( "root" ); root.Add( new Leaf( "Leaf A" )); root.Add( new Leaf( "Leaf B" )); Composite comp = new Composite( "Composite X" ); comp.Add( new Leaf( "Leaf XA" ) ); comp.Add( new Leaf( "Leaf XB" ) ); root.Add( comp ); root.Add( new Leaf( "Leaf C" )); // Add and remove a leaf Leaf l = new Leaf( "Leaf D" ); root.Add( l ); root.Remove( l ); // Recursively display nodes root.Display( 1 ); }} 透明式的合成模式實(shí)現(xiàn): 每個(gè)里都有add,remove等修改方法.
以下示例性代碼演示了安全式的合成模式代碼:
// Composite pattern -- Structural example using System;using System.Text;using System.Collections;// "Component"abstract class Component{ // Fields protected string name; // Constructors public Component( string name ) { this.name = name; } // Methods abstract public void Add(Component c); abstract public void Remove( Component c ); abstract public void Display( int depth );}// "Composite"class Composite : Component{ // Fields private ArrayList children = new ArrayList(); // Constructors public Composite( string name ) : base( name ) {} // Methods public override void Add( Component component ) { children.Add( component ); } public override void Remove( Component component ) { children.Remove( component ); } public override void Display( int depth ) { Console.WriteLine( new String( '-', depth ) + name ); // Display each of the node's children foreach( Component component in children ) component.Display( depth + 2 ); }}// "Leaf"class Leaf : Component{ // Constructors public Leaf( string name ) : base( name ) {} // Methods public override void Add( Component c ) { Console.WriteLine("Cannot add to a leaf"); } public override void Remove( Component c ) { Console.WriteLine("Cannot remove from a leaf"); } public override void Display( int depth ) { Console.WriteLine( new String( '-', depth ) + name ); }}/// <summary>/// Client test/// </summary>public class Client{ public static void Main( string[] args ) { // Create a tree structure Composite root = new Composite( "root" ); root.Add( new Leaf( "Leaf A" )); root.Add( new Leaf( "Leaf B" )); Composite comp = new Composite( "Composite X" ); comp.Add( new Leaf( "Leaf XA" ) ); comp.Add( new Leaf( "Leaf XB" ) ); root.Add( comp ); root.Add( new Leaf( "Leaf C" )); // Add and remove a leaf Leaf l = new Leaf( "Leaf D" ); root.Add( l ); root.Remove( l ); // Recursively display nodes root.Display( 1 ); }} 實(shí)例
再看看一個(gè)完整些的例子:
#include <iostream> #include <string> #include <list> using namespace std; class Component { protected: string name; public: Component(string name) :name(name) { } virtual void AddComponent(Component *component) { } virtual void RemoveComponent(Component *component) { } virtual void GetChild(int depth) { } }; class Leaf: public Component { public: Leaf(string name) :Component(name) { } void AddComponent(Component *component) { cout<<"Leaf can't add component"<<endl; } void RemoveComponent(Component *component) { cout<<"Leaf can't remove component"<<endl; } void GetChild(int depth) { string _tmpstring(depth, '-'); cout<<_tmpstring<<name<<endl; } }; class Composite:public Component { private: list<Component*> _componets; public: Composite(string name) :Component(name) { } void AddComponent(Component *component) { _componets.push_back(component); } void RemoveComponent(Component *component) { _componets.remove(component); } void GetChild(int depth) { string tmpstring (depth, '-'); cout<<tmpstring<<name<<endl; list<Component*>::iterator iter = _componets.begin(); for(; iter != _componets.end(); iter++) { (*iter)->GetChild(depth + 2); } } }; int main() { Composite *root = new Composite("root"); Leaf *leaf1 = new Leaf("leaf1"); Leaf *leaf2 = new Leaf("leaf2"); root->AddComponent(leaf1); root->AddComponent(leaf2); Composite *lay2 = new Composite("layer2"); Leaf *leaf4 = new Leaf("leaf4"); lay2->AddComponent(leaf4); Composite *lay1 = new Composite("layer1"); Leaf *leaf3 = new Leaf("leaf3"); lay1->AddComponent(leaf3); lay1->AddComponent(lay2); root->AddComponent(lay1); root->GetChild(1); cout<<endl; lay1->GetChild(1); cout<<endl; lay2->GetChild(1); delete root; delete lay1; delete lay2; delete leaf1; delete leaf2; delete leaf3; delete leaf4; system("pause"); return 0; } 輸出:





















