#組合模式(Composite Pattern)
##簡介
有個項目,是為一家在全國許多城市都有分銷機構的大公司做辦公管理系統,總部有人力資源,財務,運營等部門。但是總公司的人力資源部,財務部等辦公管理功能在所有的分公司或辦事處都需要有。我們可能希望人力資源部,財務部的管理功能可以復用于分公司。這其實就是整體與部分可以被一致對待的問題。
***組合模式:將對象組合成樹形結構以表示'部分-整體'的層次結構。組合模式使得用戶對單個對象和組合對象的使用具有一致性。***
***當你發現需求中是體現部分與整體層次的結構時,以及你希望用戶可以忽略組合對象與單個對象的不同,統一地使用組合結構中的所有對象時,就應該考慮使用組合模式了。***
###公司管理系統
公司類,抽象類或接口
```
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(Company c);//顯示 public abstract void LineOfDuty(Company c);//履行職責
}
```
具體公司類 實現接口樹枝節點
```
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();
}
}
}
```
人力資源部與財務部類 樹葉節點
```
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);
}
}
```
財務部
```
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);
}
}
```
客戶端調用
```
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);
root.Display(1);
root.LineOfDuty();
}
```
###透明方式與安全方式
透明方式,也就是說在Component中聲明所有用來管理子對象的方法,其中包括Add,Remove等。這樣實現Component接口的所有子類都具備了Add和RFemove。這樣做的好處就是葉節點和枝節點對于外界沒有區別,它們具備完全一致的行為接口。但是問題也很明顯,因為Leaf類本身不具備Add(),Remove()方法的功能,所以實現也是沒意義的。
安全方式,也就是在Component接口中不去聲明Add和Remove方法,那么字類的Leaf也不需要實現它,而是在Composite聲明所有用來管理字類對象的方法。不過由于不透明,所以樹枝類和樹葉不具有相同的接口,客戶端的調用需要做相應的判斷,帶來了不便。
***組合模式有時候又叫做部分-整體模式,它使我們樹型結構的問題中,模糊了簡單元素和復雜元素的概念,客戶程序可以向處理簡單元素一樣來處理復雜元素,從而使得客戶程序與復雜元素的內部結構解耦。***