設計模式(8) 組合模式

来源:https://www.cnblogs.com/zhixin9001/archive/2020/07/17/13332887.html
-Advertisement-
Play Games

組合模式 透明模式與安全模式 對組合的篩選遍歷 無論是在生活中還是項目中,我們經常會遇到具有“部分-整體”概念的對象,比如員工與團隊的關係,這就類似樹形結構,可能具有很多的嵌套層次和分支,把這種複雜性直接暴露給調用端是不合適的。 組合模式 藉助組合模式,可以將這類具有“部分-整體”的對象組合成樹形的 ...


  • 組合模式
  • 透明模式與安全模式
  • 對組合的篩選遍歷

無論是在生活中還是項目中,我們經常會遇到具有“部分-整體”概念的對象,比如員工與團隊的關係,這就類似樹形結構,可能具有很多的嵌套層次和分支,把這種複雜性直接暴露給調用端是不合適的。

組合模式

藉助組合模式,可以將這類具有“部分-整體”的對象組合成樹形的層次結構,並使得用戶可以對單個對象和組合對象採用相同的使用方式。
GOF對組合模式的描述為:
Compose objects into tree structures to represent part-whole hierarchies.
Compositelets clients treat individual objects and compositions of objects uniformly.
— Design Patterns : Elements of Reusable Object-Oriented Software

UML類圖:
組合模式 UML類圖

組合模式包含三個角色:

  • Leaf:葉子節點,代表單個個體,它沒有子節點。
  • Composite:組合節點,既可以包含葉子節點,也可以包含其他的組合節點,
  • Component:抽象構件,定義Leaf和Composite共有的方法和屬性,可以定義一些預設的行為或屬性。

透明模式與安全模式

在使用組合模式時,根據抽象構件類的定義形式,可將組合模式分為透明模式和安全組合兩種形式。

透明模式

透明模式中,抽象構件Component中聲明瞭所有用於管理成員對象的方法,包括add()、remove()以及getChildren()等方法,這樣做的好處是確保所有的構件類都有相同的介面。在客戶端看來,葉子對象與容器對象所提供的方法是一致的,客戶端可以相同地對待所有的對象。透明組合模式也是組合模式的標準形式,前面的類圖表示的就是透明模式。

透明模式的缺點是不夠安全,因為葉子對象和容器對象在本質上是有區別的。葉子對象不可能有下一個層次的對象,即不可能包含成員對象,因此為其提供add()、remove()以及getChildren()等方法是沒有意義的,這在編譯階段不會出錯,但在運行階段如果調用這些方法就會導致異常。

透明模式的實現代碼如下:

public abstract class Component
{
    protected IList<Component> children;

    public virtual string Name { get; set; }

    public virtual void Add(Component child)
    {
        children.Add(child);
    }

    public virtual void Remove(Component child)
    {
        children.Remove(child);
    }

    public virtual Component this[int index]
    {
        get { return children[index]; }
    }
}

public class Leaf : Component
{
    public override void Add(Component child)
    {
        throw new NotSupportedException();
    }
    public override void Remove(Component child)
    {
        throw new NotSupportedException();
    }
    public override Component this[int index] => throw new NotSupportedException();
}

public class Composite : Component
{
    public Composite()
    {
        base.children = new List<Component>();
    }
}

安全模式

安全模式則是將管理成員對象的方法從抽象構件Component轉移到了Composite,在抽象構件Component中沒有聲明任何用於管理成員對象的方法,這樣可以保證安全,葉子對象中無法調用到那些管理成員對象的方法。

安全模式的缺點是不夠透明,因為葉子構件和容器構件具有不同的方法,且容器構件中那些用於管理成員對象的方法沒有在抽象構件類中定義,因此客戶端不能完全針對抽象編程,必須有區別地對待葉子構件和容器構件。

對組合的篩選遍歷

將對象組合成樹形結構後,要使用這些對象,就需要用遍歷樹形結構的方式來獲取這些對象。
比如對於上面代碼中的Component,如果需要獲取全部結點的Names屬性

實現代碼可以為:

public List<string> names = new List<string>();
public virtual IEnumerable<string> GetNameList()
{
    GetNameList(names);
    return names;
}


private virtual void GetNameList(List<string> names)
{
    names.Add(this.Name);
    if (children != null && children.Count > 0)
    {
        foreach (Component child in children)
        {
            child.GetNameList(names);
        }
    }
}

但有的時候往往會遇到一些定製化的遍歷需求,比如只獲取Leaf結點(僅列出一個所有員工的名單),只獲取Composite結點(僅列出所有部門領導的信息)等等,對於這些需求如果一一實現比較麻煩,且需要頻繁變化,可以採用一種更通用的方式,類似Linq中Where篩選那樣,調用的同時把篩選條件也傳入。

對GetNameList方法的擴展:

public virtual IEnumerable<string> GetNameList(Func<Component, bool> isMatchFunc)
{
    GetNameList(names, isMatchFunc);
    return names;
}

public virtual void GetNameList(List<string> names, Func<Component, bool> isMatchFunc)
{
    if (isMatchFunc == null || isMatchFunc(this))
    {
        names.Add(this.Name);
    }
    if (children != null && children.Count > 0)
    {
        foreach (Component child in children)
        {
            child.GetNameList(names, isMatchFunc);
        }
    }
}

參考書籍:
王翔著 《設計模式——基於C#的工程化實現及擴展》


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在PostgreSQL資料庫之間進行跨庫操作的方式 dblink postgres_fdw 本文先說說dblink;dblink是一個支持從資料庫會話中連接到其他PostgreSQL資料庫的插件。在其他資料庫跨庫操作也是採用dblink的方式 一、安裝dblink PostgreSQL插件dblin ...
  • 什麼是大事務 運行時間比較長,長時間未提交的事務就可以稱為大事務 大事務產生的原因 操作的數據比較多 大量的鎖競爭 事務中有其他非DB的耗時操作 。。。 大事務造成的影響 併發情況下,資料庫連接池容易被撐爆 鎖定太多的數據,造成大量的阻塞和鎖超時 執行時間長,容易造成主從延遲 回滾所需要的時間比較長 ...
  • 上篇筆記講到了聚合函數的實現並且帶大家看了聚合函數是如何註冊到ClickHouse之中的並被調用使用的。這篇筆記,筆者會續上上篇的內容,將剖析一把ClickHouse聚合流程的整體實現。 第二篇文章,我們來一起看看聚合流程的實現~~ 上車! 1.基礎知識的梳理 ClickHouse的實現介面 Blo ...
  • 數據字典是oracle存放有關資料庫信息的地方,幾乎所有的系統信息和對象信息都可在數據字典中進行查詢。數據字典是oracle資料庫系統的信息核心,它是一組提供有關資料庫信息的表和視圖的集合,這些表和視圖是只讀的。它是隨著資料庫的建立而建立的,當資料庫執行特定動作時數據字典也會自動更新。數據一覽與數據 ...
  • 目前CSDN,博客園,簡書同步發表中,更多精彩歡迎訪問我的gitee pages HDFS NN,2NN,DN及HDFS2.x新特性 NameNode和SecondaryNameNode(重點) NN和2NN工作機制 第一階段:NameNode啟動 第一次啟動NameNode格式化後,創建fsima ...
  • 排序查詢 * 語法:order by 子句 * order by 排序欄位1 排序方式1 , 排序欄位2 排序方式2... * 排序方式: * ASC:升序,預設的。 * DESC:降序。 * 註意: * 如果有多個排序條件,則當前邊的條件值一樣時,才會判斷第二條件。 聚合函數:將一列數據作為一個整 ...
  • 之前一個手機觸屏壞了,最近需要使用手機做一些操作;今天嘗試使用adb工具進行調試; 安卓開發者網站:https://developer.android.google.cn/ adb調試工具介紹:https://developer.android.google.cn/studio/command-li ...
  • 添加ksoap2-android-assembly-3.6.3-jar-with-dependencies.jar包 創建KsoapHelper類 public class KsoapHelper { public static int timeOut = 30000; public static ...
一周排行
    -Advertisement-
    Play Games
  • Timer是什麼 Timer 是一種用於創建定期粒度行為的機制。 與標準的 .NET System.Threading.Timer 類相似,Orleans 的 Timer 允許在一段時間後執行特定的操作,或者在特定的時間間隔內重覆執行操作。 它在分散式系統中具有重要作用,特別是在處理需要周期性執行的 ...
  • 前言 相信很多做WPF開發的小伙伴都遇到過表格類的需求,雖然現有的Grid控制項也能實現,但是使用起來的體驗感並不好,比如要實現一個Excel中的表格效果,估計你能想到的第一個方法就是套Border控制項,用這種方法你需要控制每個Border的邊框,並且在一堆Bordr中找到Grid.Row,Grid. ...
  • .NET C#程式啟動閃退,目錄導致的問題 這是第2次踩這個坑了,很小的編程細節,容易忽略,所以寫個博客,分享給大家。 1.第一次坑:是windows 系統把程式運行成服務,找不到配置文件,原因是以服務運行它的工作目錄是在C:\Windows\System32 2.本次坑:WPF桌面程式通過註冊表設 ...
  • 在分散式系統中,數據的持久化是至關重要的一環。 Orleans 7 引入了強大的持久化功能,使得在分散式環境下管理數據變得更加輕鬆和可靠。 本文將介紹什麼是 Orleans 7 的持久化,如何設置它以及相應的代碼示例。 什麼是 Orleans 7 的持久化? Orleans 7 的持久化是指將 Or ...
  • 前言 .NET Feature Management 是一個用於管理應用程式功能的庫,它可以幫助開發人員在應用程式中輕鬆地添加、移除和管理功能。使用 Feature Management,開發人員可以根據不同用戶、環境或其他條件來動態地控制應用程式中的功能。這使得開發人員可以更靈活地管理應用程式的功 ...
  • 在 WPF 應用程式中,拖放操作是實現用戶交互的重要組成部分。通過拖放操作,用戶可以輕鬆地將數據從一個位置移動到另一個位置,或者將控制項從一個容器移動到另一個容器。然而,WPF 中預設的拖放操作可能並不是那麼好用。為瞭解決這個問題,我們可以自定義一個 Panel 來實現更簡單的拖拽操作。 自定義 Pa ...
  • 在實際使用中,由於涉及到不同編程語言之間互相調用,導致C++ 中的OpenCV與C#中的OpenCvSharp 圖像數據在不同編程語言之間難以有效傳遞。在本文中我們將結合OpenCvSharp源碼實現原理,探究兩種數據之間的通信方式。 ...
  • 一、前言 這是一篇搭建許可權管理系統的系列文章。 隨著網路的發展,信息安全對應任何企業來說都越發的重要,而本系列文章將和大家一起一步一步搭建一個全新的許可權管理系統。 說明:由於搭建一個全新的項目過於繁瑣,所有作者將挑選核心代碼和核心思路進行分享。 二、技術選擇 三、開始設計 1、自主搭建vue前端和. ...
  • Csharper中的表達式樹 這節課來瞭解一下表示式樹是什麼? 在C#中,表達式樹是一種數據結構,它可以表示一些代碼塊,如Lambda表達式或查詢表達式。表達式樹使你能夠查看和操作數據,就像你可以查看和操作代碼一樣。它們通常用於創建動態查詢和解析表達式。 一、認識表達式樹 為什麼要這樣說?它和委托有 ...
  • 在使用Django等框架來操作MySQL時,實際上底層還是通過Python來操作的,首先需要安裝一個驅動程式,在Python3中,驅動程式有多種選擇,比如有pymysql以及mysqlclient等。使用pip命令安裝mysqlclient失敗應如何解決? 安裝的python版本說明 機器同時安裝了 ...