部分整體借卧,樹形結(jié)構(gòu),『組合模式』來幫忙

目錄:設(shè)計模式之小試牛刀
源碼路徑:Github-Design Pattern


定義:(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é)果如下:

遍歷方式
輸出結(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)點

  1. 擴展性好:樹枝和樹葉節(jié)點可以自由擴展夏志,符合OCP乃坤。
  2. 方便高層調(diào)用:局部和整體對高層模塊來說沒有區(qū)別,樹形機構(gòu)中的所有節(jié)點都是Component沟蔑。

缺點

  1. 不是面向接口編程湿诊,與依賴倒置原則相違背。

應(yīng)用場景:

  1. 樹形結(jié)構(gòu)
  2. 部分整體關(guān)系
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末溉贿,一起剝皮案震驚了整個濱河市枫吧,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌宇色,老刑警劉巖九杂,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異宣蠕,居然都是意外死亡例隆,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門抢蚀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來镀层,“玉大人,你說我怎么就攤上這事〕辏” “怎么了吴侦?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長坞古。 經(jīng)常有香客問我备韧,道長,這世上最難降的妖魔是什么痪枫? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任织堂,我火速辦了婚禮,結(jié)果婚禮上奶陈,老公的妹妹穿的比我還像新娘易阳。我一直安慰自己,他們只是感情好吃粒,可當(dāng)我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布潦俺。 她就那樣靜靜地躺著,像睡著了一般声搁。 火紅的嫁衣襯著肌膚如雪黑竞。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天疏旨,我揣著相機與錄音很魂,去河邊找鬼。 笑死檐涝,一個胖子當(dāng)著我的面吹牛遏匆,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播谁榜,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼幅聘,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了窃植?” 一聲冷哼從身側(cè)響起帝蒿,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎巷怜,沒想到半個月后葛超,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡延塑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年绣张,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片关带。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡侥涵,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情芜飘,我是刑警寧澤务豺,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站嗦明,受9級特大地震影響冲呢,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜招狸,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望邻薯。 院中可真熱鬧裙戏,春花似錦、人聲如沸厕诡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽灵嫌。三九已至壹罚,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間寿羞,已是汗流浹背猖凛。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留绪穆,地道東北人辨泳。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像玖院,于是被迫代替她去往敵國和親菠红。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容