定義:(Composite Pattern)
將對象組合成樹形結(jié)構(gòu)以表示“部分-整體”的層次結(jié)構(gòu)敦姻,使得用戶對單個對象和組合對象的使用具有一致性瘾境。
又稱為部分整體模式,合成模式镰惦。
類圖:
從圖中可以看到迷守,主要有以下幾個角色:
- Component(根節(jié)點): 定義組合對象公用的方法或?qū)傩?/li>
- Composite(樹枝節(jié)點):組合樹枝節(jié)點和樹葉節(jié)點構(gòu)造一個樹形結(jié)構(gòu)
- Leaf(葉子節(jié)點):最小單元
啟示:
提到組合模式,大家可能會覺得陌生旺入,但是提到樹形結(jié)構(gòu)兑凿,大家可能就很熟悉,畢竟生活中到處都是“樹”茵瘾。那在Coding中礼华,最常見的樹形結(jié)構(gòu)比如組織架構(gòu),菜單拗秘,權(quán)限設(shè)計圣絮,文件管理等等。那這次我們就用組織架構(gòu)來談?wù)劷M合模式的應(yīng)用雕旨。一個公司是由部門組成的扮匠,部門下是員工捧请,典型的組合模式。
就一般公司的組織架構(gòu)而言棒搜,最上層為CEO疹蛉,也就是根節(jié)點,往下就是各部門經(jīng)理力麸,每個部門經(jīng)理可能負(fù)責(zé)有多個項目可款,每個項目都安排有對應(yīng)的項目組長負(fù)責(zé),那項目組就是由項目成員組成了末盔。為了演示方便筑舅,我們的層級就不往下深入了。下面是我簡化的組織架構(gòu)圖陨舱。
代碼:
在我們的組織架構(gòu)中我們主要分為三塊翠拣,組織、部門游盲、員工误墓。
首先來看看Component角色,對應(yīng)代碼中的Organization
益缎。其中主要定義了公用的屬性谜慌,職位、姓名及上級節(jié)點莺奔。上級節(jié)點的主要作用是用來從下往上遍歷欣范。
/// <summary>
/// 組織架構(gòu)
/// </summary>
public abstract class Organization
{
/// <summary>
/// 成員姓名
/// </summary>
public string MemberName { get; set; }
/// <summary>
/// 成員職位
/// </summary>
public string MemberPosition { get; set; }
/// <summary>
/// 直接上級
/// </summary>
public Organization ParentNode { get; set; }
public void Display()
{
var basicInfo = string.Format("姓名:{0},職位:{1}", MemberName, MemberPosition);
var parentInfo = ParentNode == null
? ""
: string.Format(",直接上級:『姓名:{0},職位:{1}』", ParentNode.MemberName, ParentNode.MemberPosition);
Console.WriteLine(basicInfo + parentInfo);
}
}
再來看看對應(yīng)Composite角色令哟,部門的實現(xiàn)恼琼。在組織架構(gòu)中,部門是組合的關(guān)鍵屏富,也就是樹枝節(jié)點晴竞。
/// <summary>
/// 部門
/// </summary>
public class Department : Organization
{
private readonly List<Organization> _organizationInfo = new List<Organization>();
public Department(string departmentName, string charge)
{
MemberPosition = departmentName;
MemberName = charge;
}
public void Add(Organization org)
{
_organizationInfo.Add(org);
org.ParentNode = this;
}
public void Remove(Organization org)
{
_organizationInfo.Remove(org);
}
public List<Organization> GetDepartmentMembers()
{
return _organizationInfo;
}
}
最后來看樹葉節(jié)點,員工的實現(xiàn)狠半。因為我們在組織節(jié)點未定義抽象方法噩死,所以,直接繼承自Organization
即可神年。
/// <summary>
/// 員工
/// </summary>
public class Member : Organization
{
}
來看看場景類:
internal class Program
{
private static void Main(string[] args)
{
Console.WriteLine("組合模式:");
Console.WriteLine("-------------------");
var organzation = new Department("CEO", "老總");
var developDepart = new Department("研發(fā)部經(jīng)理", "研哥");
organzation.Add(developDepart);
var projectA = new Department("Erp項目組長", "E哥");
developDepart.Add(projectA);
var memberX = new Member {MemberPosition = "開發(fā)工程師", MemberName = "開發(fā)X"};
var memberY = new Member {MemberPosition = "開發(fā)工程師", MemberName = "開發(fā)Y"};
var memberZ = new Member {MemberPosition = "測試工程師", MemberName = "測試Z"};
projectA.Add(memberX);
projectA.Add(memberY);
projectA.Add(memberZ);
Console.WriteLine("組合模式:從上往下遍歷");
DisplayStructure(organzation);
Console.WriteLine("-------------------");
Console.WriteLine();
Console.WriteLine("組合模式:從下往上遍歷");
FindParent(memberX);
Console.WriteLine("-------------------");
Console.ReadLine();
}
/// <summary>
/// 正序排序
/// </summary>
/// <param name="org"></param>
private static void DisplayStructure(Organization org)
{
if (org.ParentNode == null)
org.Display();
var departMent = (Department) org;
foreach (var depart in departMent.GetDepartmentMembers())
{
depart.Display();
if (!(depart is Member))
DisplayStructure((Department) depart);
}
}
/// <summary>
/// 倒序排序
/// </summary>
/// <param name="member"></param>
private static void FindParent(Organization member)
{
member.Display();
while (member.ParentNode != null)
{
member.ParentNode.Display();
member = member.ParentNode;
}
}
}
在場景類中已维,我們創(chuàng)建了組織架構(gòu)圖中左邊的這條線,并提供了從上往下已日、從下往上兩種遍歷方法垛耳。輸出結(jié)果如下:
本實例主要用于簡單演示組合模式的用法,還有很多需要完善的地方。小伙伴不妨想一想如果在我們真實的項目中該如何設(shè)計呢艾扮?
擴展
在組合模式中有一種透明組合模式,之所以透明占婉,是因為將composite角色中也就是樹葉節(jié)點的用來組合的方法挪到了component角色根節(jié)點抽象類中定義泡嘴,再由樹枝樹葉單獨實現(xiàn)。這樣是將樹枝和樹葉的結(jié)構(gòu)保存了一致逆济,但引入了一個問題酌予,因為樹葉節(jié)點最小單元是不需要去組裝的,但是又必須實現(xiàn)抽象類定義的組合方法奖慌,就只能給一個空實現(xiàn)throw new NotImplementedException()
抛虫,處理不當(dāng)就會拋出異常。
那相對來說简僧,我們上例就是組合模式的安全實現(xiàn)建椰。
總結(jié):
組合模式的目的是簡化部分整體的組裝方式及遍歷方式。高層模塊(客戶端)通過統(tǒng)一處理Composite角色岛马,就可以完成部分整體的組裝和拆解棉姐。根據(jù)自己的需求,在Component中定義公用的方法由樹枝樹葉實現(xiàn)啦逆,比如:通過定義設(shè)置獲取上級節(jié)點的方法伞矩,即可完成從下往上遍歷。
優(yōu)缺點:
優(yōu)點
- 擴展性好:樹枝和樹葉節(jié)點可以自由擴展夏志,符合OCP乃坤。
- 方便高層調(diào)用:局部和整體對高層模塊來說沒有區(qū)別,樹形機構(gòu)中的所有節(jié)點都是Component沟蔑。
缺點
- 不是面向接口編程湿诊,與依賴倒置原則相違背。
應(yīng)用場景:
- 樹形結(jié)構(gòu)
- 部分整體關(guān)系