通俗易懂設計模式解析——組合模式

前言

  今天介紹的是結構型設計模式中的第四個模式,也就是組合模式(Composite Pattern)。組合模式也好理解,就拿咱們電腦的文件及文件夾來講吧,這就是一個較好的組合模式的例子。一個目錄下面包含文件及文件夾,文件夾下面也包含文件或文件夾。在這樣一層層下來,咱們能夠想象。他彷佛像極了那個樹狀圖。而組合模式是依據樹型結構來組合對象。用來表示部分—總體層次關係。html

組合模式介紹

1、來由

  在咱們軟件系統開發中,會遇到簡單對象與複雜對象一塊兒使用的狀況,就比如剛剛說的文件目錄同樣,能夠包含文件和文件夾,文件夾下面也能夠包含文件和文件夾。可是因爲簡單對象和複雜對象在功能使用上仍是有必定的區別的,可能會形成客戶端調用時較爲麻煩。這時候就須要將簡單對象和複雜對象統一一致對待。然而組合模式也就是解決這一麻煩的。設計模式

2、意圖

  將對象組合成樹形結構以表示"部分-總體"的層次結構。組合模式使得用戶對單個對象和組合對象的使用具備一致性。安全

3、案例圖

 

 

 

 

4、組合模式代碼示例

  看上面案例圖,能夠發現組合模式通常包含如下部分:ide

抽象構件角色:這是一個抽象角色,它給參加組合的對象定義了公共的接口和行爲,在透明式的組合模式中,包含了對全部子對象的管理。可是在安全式的組合模式中,這裏不定義管理子對象的方法,而是由樹枝構件定義給出。spa

樹葉構件:樹葉構件意味着沒有下級對象,定義了參加組合對象的原始行爲。設計

樹枝構件:表明有下級對象(樹枝或樹葉都有可能),給出管理其子類的對象。code

 

在組合模式中,細分爲兩種形式。一、透明式組合模式。二、安全式組合模式。這裏咱們能夠看看何爲透明式何爲安全式:htm

透明式:對象

  抽象構件角色定義公共的接口和行爲,這裏呢就包括對本對象的操做也包含其子對象的操做的。可是樹葉構件對象沒有其子類。可是依然繼承其功能接口和行爲。這裏在接口和行爲上,不管調用樹枝構件仍是樹葉構件都是同樣的。這就屬於透明式了。blog

安全式:
  由上面透明式講的,樹葉構件也會包含操做本身和子對象的接口和行爲,可是沒有其子對象怎麼辦呢?固然是能夠空着不寫,但會空。可是萬一實現調用了呢?對吧,仍是有必定的安全隱患的。那麼安全式也就是說抽象構件包含操做自己對象的接口和行爲,那麼樹葉構件也就包含操做自己對象的接口和行爲了。樹枝構件則實現操做自身對象的接口和行爲的同時,還須要實現操做其子類的對象的接口和行爲。

 

就按開始所講的文件目錄的案例,咱們經過代碼一塊兒看看,在代碼中如何實現組合模式的,這樣也能夠更方便快捷的瞭解記憶:

 透明式:

namespace Composite_Pattern { /// <summary>
    /// 透明式組合模式 /// </summary>
    class CompositePattern { } #region 抽象構件角色——抽象文件目錄============
    public abstract class Files { /// <summary>
        /// 增長子對象 /// </summary>
        public abstract void Add(Files files = null, string Name = null); /// <summary>
        /// 刪除子對象 /// </summary>
        public abstract void Remove(Files files=null, string Name = null); /// <summary>
        /// 操做自己對象 /// </summary>
        public abstract void Open(string Name); } #endregion

    #region 樹葉構件——文件類型========================
    /// <summary>
    /// TXT文本 /// </summary>
    public sealed class BookTxt : Files { public override void Add(Files files=null, string Name = null) { throw new NotImplementedException("不存在添加子類操做"); } public override void Remove(Files files=null, string Name = null) { throw new NotImplementedException("不存在刪除子類操做"); } public override void Open(string Name) { Console.WriteLine($"打開一個名爲【{Name}】txt文本"); } } #endregion

    #region 樹枝構件——文件夾類型=================
    public class SubFiles : Files { public override void Add(Files files=null, string Name = null) { if (files != null) { Console.WriteLine($"添加一個名爲【{Name}】的文件夾"); } else { Console.WriteLine($"添加一個名爲【{Name}】的txt文本"); } } public override void Remove(Files files=null, string Name = null) { if (files != null ) { Console.WriteLine($"刪除一個名爲【{Name}】的文件夾"); } else { Console.WriteLine($"刪除一個名爲【{Name}】的txt文本"); } } public override void Open(string Name) { Console.WriteLine($"打開當前名爲【{Name}】文件夾文件夾"); } } #endregion }
    class Program { static void Main(string[] args) { //操做樹葉自己文件
            Files bookTxt = new BookTxt(); bookTxt.Open("文本文件一"); //新增文件夾
            Files subFiles = new SubFiles(); subFiles.Open("文件一"); subFiles.Add(new SubFiles(), "文件二"); //刪除文件
            subFiles.Remove(Name: "文本文件二"); Console.ReadLine(); } }

 

 安全式:

namespace Composite_Pattern1 { /// <summary>
    /// 安全式組合模式 /// </summary>
    class CompositePattern { } #region 抽象構件角色——抽象文件目錄============
    public abstract class Files { /// <summary>
        /// 操做自己對象 /// </summary>
        public abstract void Open(string Name); } #endregion

    #region 樹葉構件——文件類型========================
    /// <summary>
    /// TXT文本 /// </summary>
    public sealed class BookTxt : Files { public override void Open(string Name) { Console.WriteLine($"打開一個名爲【{Name}】txt文本"); } } #endregion

    #region 抽象樹枝構件——安全模式,開始定義子類對象操做接口和行爲=================
    public abstract  class SubFiles : Files { public abstract void Add(Files files = null, string Name = null); public abstract void Remove(Files files = null, string Name = null); public override void Open(string Name) { Console.WriteLine($"打開當前名爲【{Name}】文件夾"); } } #endregion

    #region 具體樹枝構件——具體實現類
    public class AbSubFiles : SubFiles { public override void Add(Files files = null, string Name = null) { if (files != null) { Console.WriteLine($"添加一個名爲【{Name}】的文件夾"); } else { Console.WriteLine($"添加一個名爲【{Name}】的txt文本"); } } public override void Remove(Files files = null, string Name = null) { if (files != null) { Console.WriteLine($"刪除一個名爲【{Name}】的文件夾"); } else { Console.WriteLine($"刪除一個名爲【{Name}】的txt文本"); } } public override void Open(string Name) { Console.WriteLine($"打開當前名爲【{Name}】文件夾"); } } #endregion }

 

    class Program1 { static void Main(string[] args) { //操做樹葉自己文件
            BookTxt bookTxt = new BookTxt(); bookTxt.Open("文本文件一"); //新增文件夾
            AbSubFiles subFiles = new AbSubFiles(); subFiles.Open("文件一"); subFiles.Add(new AbSubFiles(), "文件二"); //刪除文件
            subFiles.Remove(Name: "文本文件二"); Console.ReadLine(); } }

 

使用場景及優缺點

1、使用場景

一、部分——總體的環境。例如樹型菜單,文件管理

二、用戶但願對簡單對象與複雜對象擁有一致的操做時

2、優勢

一、組合模式使得處理簡單對象和複雜對象有一致的操做,無需關心處理的簡單對象仍是複雜對象

二、更簡單快捷的加入新的節點

3、缺點

一、使得設計複雜,難於理清層次

二、在使用透明式的時候違背了接口分離原則,可是在使用安全式的時候又違背了依賴倒置原則

總結

  到這裏組合模式就介紹完了。這裏須要說起的是在使用透明式組合模式時,樹葉構件繼承了操做子類的接口和行爲,可是它並無子類。在接口分離原則中提到——客戶不該被強迫依賴它不使用的方法。因此這裏違背了其原則,可是都遵循了依賴倒置原則,依賴於抽象。在實現安全式組合模式時,在客戶端調用時依賴於具體實現,也就違背了依賴倒置原則,可是卻將樹葉操做與樹枝構件操做分離,符合接口分離原則。在實現組合模式中不一樣形式實現有不一樣的問題。這就須要根據咱們實際狀況去衡量該如何使用了。

只有經歷過地獄般的折磨,纔有征服天堂的力量。只有流過血的手指才能彈出世間的絕唱。

    C#設計模式系列目錄

歡迎你們掃描下方二維碼,和我一塊兒踏上設計模式的闖關之路吧!

  

相關文章
相關標籤/搜索