1.概述
組合模式有時候又叫做部分-整體模式,它使我們樹型結構的問題中,模糊了簡單元素和復雜元素的概念,客戶程序可以向處理簡單元素一樣來處理復雜元素,從而使得客戶程序與復雜元素的內部結構解耦。
組合模式(Composite Pattern):將對象組合成樹形結構以表示‘部分-整體’的層次結構,組合模式使得用戶對單個對象和組合對象的使用具有一致性。
組合模式結構圖如下:
結構圖說明:
(1)Component:組合中的對象聲明接口,在適當情況下實現所有類共有的默認行為,聲明一個接口用于訪問和管理Component的子組件。在遞歸結構中定義一個接口,用于訪問一個父部件,并在合適的情況下實現它。(可選)
(2)Leaf:在組合中表示葉節點,葉節點沒有子節點,定義對象的基本行為。
(3)Composite:定義有子部件的那些部件的行為,存儲子部件并在Component接口實現與子部件有關的操作。
(4)Client:通過Component接口操作組合部件的對象。
組合模式基本代碼:
public abstract class Component
{
protected string name;
public Component(string name)
{
this.name = name;
}
public abstract void Add(Component c);
public abstract void Remove(Component c);
public abstract void Display(int depth);
}
Composite:
public class Composite : Component
{
private List<Component> children = new List<Component>();
public Composite(string name)
: base(name)
{ }
public override void Add(Component c)
{
children.Add(c);
}
public override void Remove(Component c)
{
children.Remove(c);
}
public override void Display(int depth)
{
Console.WriteLine(new String('-', depth) + name);
foreach (Component component in children)
{
component.Display(depth + 2);
}
}
}
Leaf:
public class Leaf : Component
{
public Leaf(string name)
: base(name)
{ }
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);
}
}
客戶端:
public class Program
{
static void Main(string[] args)
{
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);
Composite comp2 = new Composite("Composite XY");
comp2.Add(new Leaf("Leaf XYA"));
comp2.Add(new Leaf("Leaf XYB"));
comp.Add(comp2);
root.Add(new Leaf("Leaf C"));
Leaf leaf = new Leaf("Leaf D");
root.Add(leaf);
root.Remove(leaf);
root.Display(1);
Console.Read();
}
}
可以看出,Composite類型的對象可以包含其它Component類型的對象。換而言之,Composite類型對象可以含有其它的樹枝(Composite)類型或樹葉(Leaf)類型的對象。
組合模式的實現根據所實現接口的區別分為兩種形式,分別稱為安全模式和透明模式。組合模式可以不提供父對象的管理方法,但組合模式必須在合適的地方提供子對象的管理方法(諸如:add、remove等)。安全式的組合模式要求管理聚集的方法只出現在樹枝構件類中,而不出現在樹葉構件中。與安全式的組合模式不同的是,透明式的組合模式要求所有的具體構件類,不論樹枝構件還是樹葉構件,均符合一個固定的接口。
透明模式:也就是說在Component中聲明所有用來管理子對象的方法,其中包括Add、Remove等。這樣實現Component接口的所有子類都具備了Add和Remove。這樣做的好處就是葉節點和枝節點對于外界沒有區別,它們具有完全一致的行為接口,但問題也很明顯,因為Leaf類本身不具備Add(),Remove()方法的功能,所以實現他是沒有意義的。
安全模式:就是在Component接口中不去聲明Add和Remove方法,那么子類的Leaf也就不需要去實現它,而是在Composite聲明所有用來管理子類對象的方法,這樣就不會出現透明模式出現的問題,不過由于不夠透明,所以葉節點和枝節點將不具有相同的接口,客戶端調用需要做相應的判斷,帶來了不便。
2.實例(大話設計模式)
大話設計模式中的公司管理系統的結構圖如下:
具體實現代碼如下:
CompanyComposite
public abstract class Company
{
protected string name;
public Company(string name)
{
this.name = name;
}
public abstract void Add(Company c);//增加
public abstract void Remove(Company c);//移除
public abstract void Display(int depth);//顯示
public abstract void LineOfDuty();//履行職責
}
public class ConcreteCompany : Company
{
private List<Company> children = new List<Company>();
public ConcreteCompany(string name)
: base(name)
{ }
public override void Add(Company c)
{
children.Add(c);
}
public override void Remove(Company c)
{
children.Remove(c);
}
public override void Display(int depth)
{
Console.WriteLine(new String('-', depth) + name);
foreach (Company component in children)
{
component.Display(depth + 2);
}
}
//履行職責
public override void LineOfDuty()
{
foreach (Company component in children)
{
component.LineOfDuty();
}
}
}
//人力資源部
public class HRDepartment : Company
{
public HRDepartment(string name)
: base(name)
{ }
public override void Add(Company c)
{
}
public override void Remove(Company c)
{
}
public override void Display(int depth)
{
Console.WriteLine(new String('-', depth) + name);
}
public override void LineOfDuty()
{
Console.WriteLine("{0} 員工招聘培訓管理", name);
}
}
//財務部
public class FinanceDepartment : Company
{
public FinanceDepartment(string name)
: base(name)
{ }
public override void Add(Company c)
{
}
public override void Remove(Company c)
{
}
public override void Display(int depth)
{
Console.WriteLine(new String('-', depth) + name);
}
public override void LineOfDuty()
{
Console.WriteLine("{0} 公司財務收支管理", name);
}
}
客戶端代碼:
Code
public class Program
{
static void Main(string[] args)
{
ConcreteCompany root = new ConcreteCompany("北京總公司");
root.Add(new HRDepartment("總公司人力資源部"));
root.Add(new FinanceDepartment("總公司財務部"));
ConcreteCompany comp = new ConcreteCompany("上海華東分公司");
comp.Add(new HRDepartment("華東分公司人力資源部"));
comp.Add(new FinanceDepartment("華東分公司財務部"));
root.Add(comp);
ConcreteCompany comp1 = new ConcreteCompany("南京辦事處");
comp1.Add(new HRDepartment("南京辦事處人力資源部"));
comp1.Add(new FinanceDepartment("南京辦事處財務部"));
comp.Add(comp1);
ConcreteCompany comp2 = new ConcreteCompany("杭州辦事處");
comp2.Add(new HRDepartment("杭州辦事處人力資源部"));
comp2.Add(new FinanceDepartment("杭州辦事處財務部"));
comp.Add(comp2);
Console.WriteLine("\n結構圖:");
root.Display(1);
Console.WriteLine("\n職責:");
root.LineOfDuty();
Console.Read();
}
}
在.NET中,一個典型的組合模式實例就是.NET的控件,如Button,TextBox和Label等,這些控件都是繼承自Control類,該類自身包含ControlCollection的集合Controls,控件和子控件的邏輯關系如下圖:
3.總結
何時采用組合模式:
1.需求重要體現部分與整體的層次結構時
2.你希望用戶忽略組合對象與單個對象的不同,用戶將統一地使用組合結構中的所有對象。
使用效果:
1.Composite模式采用樹形結構來實現普遍存在的對象容器,從而將“一對多”的關系轉化“一對一”的關系,使得客戶代碼可以一致地處理對象和對象容器,無需關心處理的是單個的對象,還是組合的對象容器。
2.將“客戶代碼與復雜的對象容器結構”解耦是Composite模式的核心思想,解耦之后,客戶代碼將與純粹的抽象接口——而非對象容器的復內部實現結構——發生依賴關系,從而更能“應對變化”。
3.Composite模式中,是將“Add和Remove等和對象容器相關的方法”定義在“表示抽象對象的Component類”中,還是將其定義在“表示對象容器的Composite類”中,是一個關乎“透明性”和“安全性”的兩難問題,需要仔細權衡。這里有可能違背面向對象的“單一職責原則”,但是對于這種特殊結構,這又是必須付出的代價。ASP.NET控件的實現在這方面為我們提供了一個很好的示范。
4.Composite模式在具體實現中,可以讓父對象中的子對象反向追溯;如果父對象有頻繁的遍歷需求,可使用緩存技巧來改善效率。
參考資料:
大化設計模式
http://terrylee.cnblogs.com/archive/2006/03/11/347919.html
原帖地址:
http://www.cnblogs.com/peida/archive/2008/09/09/1284686.html
posted on 2016-02-14 14:36
Magic 閱讀(275)
評論(0) 編輯 收藏 引用 所屬分類:
C/C++ 、
java 、
設計模式