聊聊 C# 中的 Composite 模式

?

? 寫在前面??

Composite組合模式屬于設計模式中比較熱門的一個,相信大家對它一定不像對訪問者模式那么陌生,畢竟誰又沒有遇到過樹形結構呢。不過所謂溫故而知新,我們還是從一個例子出發,起底一下這個模式吧。

? 一個簡單例子??

設想我們要建立一個公司的人事架構,在一個公司里,我們可以簡單地分為兩種員工,一種是經理(包括老板),另一種是基層員工,經理可以有下屬,而普通員工不行,我們寫出這樣的代碼。

基層員工類

這種員工是最基層的員工,沒有下屬

class?BasicLevelEmployee?//基層員工
{public?string?ID?{?get;?set;?}public?void?ShowStatus(int?indent){string?str?=?ID;str?=?str.PadLeft(ID.Length?+?indent,?'-');Console.WriteLine(str);}
}

經理類

經理可以有下屬,下屬可能是基層員工,也可能是其他經理(考慮老板這種情況,無疑其他經理也是老板的下屬),因為比基層員工多了下屬,所以也多了一些方法維護下屬屬性

class?Manager?//經理
{public?string?ID?{?get;?set;?}public?void?ShowStatus(int?indent)?{string?str?=?ID;????????????str?=?str.PadLeft(ID.Length?+?indent,?'-');Console.WriteLine(str);indent?+=?4;Subordinate.ForEach(s?=>?s.ShowStatus(indent));SubordinateManagers.ForEach(m?=>?m.ShowStatus(indent));}public?List<BasicLevelEmployee>?Subordinate?=?new?List<BasicLevelEmployee>();public?List<Manager>?SubordinateManagers?=?new?List<Manager>();//下面是經理所屬的方法public?void?AddSubordinate(BasicLevelEmployee?e)?{?Subordinate.Add(e);?}public?void?AddSubordinate(Manager?e)?{?SubordinateManagers.Add(e);?}public?void?RemoveSubordinate(BasicLevelEmployee?e)?{?Subordinate.Remove(e);?}public?void?RemoveSubordinate(Manager?e)?{?SubordinateManagers.Remove(e);?}??????
}

公司架構類

公司架構類非常簡單,只需要掌握最大的BOSS,整個公司人事架構都可以順藤摸瓜的展示出來

class?CompanyHierachy
{public?Manager?BOSS?{?get;?set;?}public?void?ShowStatus(){BOSS.ShowStatus(0);}
}

客戶端代碼

假設這個公司的結構很單純,除了老板就是開發部門和財務部門,各個部門分設經理是,所以我們寫出代碼如下

class?Program
{static?void?Main(string[]?args){//老板Manager?boss?=?new?Manager()?{?ID?=?"BOSS"?};//開發部門經理Manager?devManager?=?new?Manager()?{?ID?=?"Dev?Manager"?};//財務部門經理Manager?financeManager?=?new?Manager()?{?ID?=?"Finance?Manager"?};//開發組長Manager?devLead?=?new?Manager()?{?ID?=?"Dev?Lead"?};//測試組長Manager?qcLead?=?new?Manager()?{?ID?=?"QC?Lead"?};boss.AddSubordinate(devManager);boss.AddSubordinate(financeManager);financeManager.AddSubordinate(new?BasicLevelEmployee()?{?ID?=?"Purchase"?});devManager.AddSubordinate(devLead);devManager.AddSubordinate(qcLead);devLead.AddSubordinate(new?BasicLevelEmployee()?{?ID?=?"Developer1"?});devLead.AddSubordinate(new?BasicLevelEmployee()?{?ID?=?"Developer2"?});qcLead.AddSubordinate(new?BasicLevelEmployee()?{?ID?=?"QuanityControl1"?});qcLead.AddSubordinate(new?BasicLevelEmployee()?{?ID?=?"QuanityControl2"?});CompanyHierachy?company?=?new?CompanyHierachy()?{?CEO?=?boss?};company.ShowStatus();}
}

代碼非常簡單,不需要更多解釋了,運行后得到結果

948dd6137810ee37d7ae9cd3d3afee5d.png

一切正常,代碼是工作的,公司架構建立成功了。

? 再想一下??

但是想想,這樣的代碼真的好嗎?感覺起碼有兩個地方我們可以改進。

  1. 1. 基層員工和經理其實有太多的共性(屬性和方法),可以利用抽象思維,讓他們繼承自同一種東西嗎?

  2. 2. 在經理類中我們維護了多個下屬列表,如果以后再加一個實習生,是不是我們又得創建更多的列表?如果我們使用了繼承,這個問題還會存在嗎?

基于此,利用抽象思維讓經理和員工繼承自同一個類(雇員)勢在必行。在抽象之后,經理類會繼承自雇員并且也內含雇員列表,可能第一次見到這種包含自身父類列表的設計方式會讓人感覺不習慣,但不用擔心,這其實是一種比較常見的設計方式。這種既有繼承也有合成的結構,就是組合模式的精髓。

? 使用組合模式進行重構??

組合模式屬于結構型設計模式,它利用類型層級和聚合層級構造更大的復合結構

說的更加直白一點,當對象的局部結構和對象自身相同的情況下,我們可以使用繼承加上聚合的方式來組合代碼,比如剛剛提到的例子中

964ed969091d0fb963668dd17b3b83c0.png

觀察一下,對于Boss來說,它的局部結構,即DevManager和FinanceManager與它自己的結構有何區別?都是樹結構,無非就是根節點不一樣而已,所以于情于理這一塊可以用繼承加聚合來重構。

那么心細的朋友肯定發現了,有些操作是經理類獨有的,這些操作我們是應該抽象到和基層員工共同的父類雇員類嗎?對于這個問題,一般有兩種解決方案。

透明型

a2b7ca37fb57a25f412b477ad71e3f65.png

在此設計中,子類方法的并集被提煉到了共有父類,哪怕這些方法對于某些子類根本不需要,這樣的好處是客戶端在使用的時候根本不需要知道對象糾結是哪個子類,對客戶端透明,所以得名。當前設計多采用這種。

安全型

7c4a2c4a50a41da02d56783fe04ec7e4.png

安全型設計非常保守,只會提煉子類交集的方法到父類,這樣的好處是絕對安全,客戶端絕對不可能在BasicLevelEmployee對象上面調用AddSubordinate或者RemoveSubordinate。但有時候會面臨向下轉型的情況。

重構后的代碼(透明型)

抽象出共同父類雇員類,使用透明型,所有的子類方法都提煉到這個類

abstract?class?Employee
{public?string?ID?{?get;?set;?}public?abstract?void?ShowStatus(int?indent);//因為是透明型,所以基層員工用不上的方法也會被抽象到父類public?abstract?void?AddSubordinate(Employee?e);public?abstract?void?RemoveSubordinate(Employee?e);
}

對于基層員工,如果客戶端無意間調用了不該使用的方法,這基本是一個明確的、表明客戶端代碼出現了邏輯問題的信號,這種情況直接拋出異常,能更快地暴露出問題

class?BasicLevelEmployee?:?Employee
{public?override?void?ShowStatus(int?indent){string?str?=?ID;str?=?str.PadLeft(ID.Length?+?indent,?'-');Console.WriteLine(str);}public?override?void?AddSubordinate(Employee?e){throw?new?NotImplementedException();}public?override?void?RemoveSubordinate(Employee?e){throw?new?NotImplementedException();}
}

在經理類中,得益于共有父類Employee,我們可以用一個列表裝下所有的下屬,不論下屬是基層員工,還是經理,抑或是未來可能添加的實習生。畢竟他們都是雇員嘛

class?Manager?:?Employee
{public?override?void?ShowStatus(int?indent){string?str?=?ID;str?=?str.PadLeft(ID.Length?+?indent,?'-');Console.WriteLine(str);indent?+=?4;Subordinate.ForEach(s?=>?s.ShowStatus(indent));}public?List<Employee>?Subordinate?=?new?List<Employee>();//下面是經理所屬的方法public?override?void?AddSubordinate(Employee?e)?{?Subordinate.Add(e);?}public?override?void?RemoveSubordinate(Employee?e)?{?Subordinate.Remove(e);?}
}

公司架構類和客戶端代碼調用保持不變,運行結果一致,重構成功。

可以看到,在使用了組合模式之后,現在的代碼不但消除了冗余(不用再去維護多個下屬列表),也更具有抵御未來變化的能力,這樣的結構比起原來,當然是更加合理的。這就是結構型設計模式的用武之地,讓對象的結構更加的合理,更加的易于擴展。

這就是關于Composite組合模式的介紹,鑒于筆者能力有限,如果大家對于這篇文章中所講有其他看法,歡迎留言討論。

> 作者:老胡寫代碼

> 原文:https://www.cnblogs.com/deatharthas/p/16390116.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/285721.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/285721.shtml
英文地址,請注明出處:http://en.pswp.cn/news/285721.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

140種Python標準庫、第三方庫和外部工具都有了

導讀&#xff1a;Python數據工具箱涵蓋從數據源到數據可視化的完整流程中涉及到的常用庫、函數和外部工具。其中既有Python內置函數和標準庫&#xff0c;又有第三方庫和工具。 這些庫可用于文件讀寫、網絡抓取和解析、數據連接、數清洗轉換、數據計算和統計分析、圖像和視頻處理…

【CC精品教程】任務一:CC新建工程、添加照片、相機參數設置、選擇坐標系統

《無人機航空攝影測量精品教程》合集目錄(Pix4d、CC、EPS、PhotoScan、Inpho) 同Pix4d一樣,CC(Context Capture),也稱Smart 3D,也是無人機航測中人手必備的一款軟件,在空三運算,三維模型構建等傾斜攝影測量方面有很大的優勢,精度也相當高。本CC系列精品教程從項目的角…

C語言試題八十七之實現選擇排序算法

??個人主頁:個人主頁 ??系列專欄:C語言試題200例目錄 ??推薦一款刷算法、筆試、面經、拿大公司offer神器 ?? 點擊跳轉進入網站 ?作者簡介:大家好,我是碼莎拉蒂,CSDN博客專家(全站排名Top 50),阿里云博客專家、51CTO博客專家、華為云享專家 1、題目 C語言選擇排…

java concurrent之前戲synchronized

對于多線程共享資源的情況須要進行同步&#xff0c;以避免一個線程的修改被還有一個線程的修改所覆蓋。最普遍的同步方式就是synchronized。把代碼聲明為synchronized。有兩個重要后果&#xff0c;一般是指該代碼具有 原子性&#xff08;atomicity&#xff09;和 可見性&#x…

開源項目【zheng】搭建流程

2019獨角獸企業重金招聘Python工程師標準>>> 搭建過程 項目地址 https://gitee.com/shuzheng/zheng這兩篇寫的比較詳細的搭建過程&#xff0c;結合一下就沒什么問題了。 https://my.oschina.net/yzuzhang/blog/1538555http://www.jianshu.com/p/b2fb42e17b581.JDK 1…

簡述HTML DOM及其節點分類

在JavaScript中&#xff0c;document這個對象大家一定很熟悉&#xff0c;哪怕是剛剛開始學習的新人&#xff0c;也會很快接觸到這個對象。而document對象不僅僅是一個普通的JavaScript內置對象&#xff0c;它還是一個巨大API的核心對象&#xff0c;這個巨大的API就是DOM&#x…

【CC精品教程】任務二:導入像控點、差分POS,空三平差權重設置,提交自由空三

《無人機航空攝影測量精品教程》合集目錄(Pix4d、CC、EPS、PhotoScan、Inpho) 【CC精品教程】任務一:CC新建工程、添加照片、相機參數設置、選擇坐標系統 本任務接著上一個任務,繼續完成CC項目作業,主要內容有:導入像控點、選擇空間參考系統,導入差分POS,空三平差權重設…

[轉]如何進行單元測試

一、單元測試步驟 代碼編寫完成后的單元測試工作主要分為兩個步驟&#xff1a; 人工靜態檢查 人工靜態檢查是測試的第一步&#xff0c;這個階段工作主要是保證代碼算法的邏輯正確性&#xff08;盡量通過人工檢查發現代碼的邏輯錯誤&#xff09;、清晰性、規范性、一致性、算法…

WPF 基礎控件之 TabControl樣式

其他基礎控件1.Window2.Button3.CheckBox4.ComboBox5.DataGrid 6.DatePicker7.Expander8.GroupBox9.ListBox10.ListView11.Menu12.PasswordBox13.TextBox14.RadioButton15.ToggleButton16.Slider 17.TreeView TabControl 實現下面的效果1&#xff09;TabControl來實現動畫&…

開發團隊測試的難與易

做了多年的研發工程師&#xff0c;在所處的環境中&#xff0c;所接觸的開發人員中很少有看重對自己代碼進行測試這項工作的。大多研發人員往往是寫好了代碼運行起來&#xff0c;簡單做下測試&#xff0c;甚至不去測試就拋給接口使用者或者質量管理人員。而且理由很充分“沒時間…

C語言試題八十八之實現選冒泡排序算法

??個人主頁:個人主頁 ??系列專欄:C語言試題200例目錄 ??推薦一款刷算法、筆試、面經、拿大公司offer神器 ?? 點擊跳轉進入網站 ?作者簡介:大家好,我是碼莎拉蒂,CSDN博客專家(全站排名Top 50),阿里云博客專家、51CTO博客專家、華為云享專家 1、題目 C語言實現冒…

兩個數值交換位置

2019獨角獸企業重金招聘Python工程師標準>>> 先說非計算機專業都能理解的。 int a 10; int b 20; 方法一&#xff1a; int c a; a b; b c; System.out.println("a"a",b"b); 方法二&#xff1a; a a b; b a - b; a a - b; System.out…

教你如何在Android 6.0上創建系統懸浮窗

郭霖大神的文章:http://mp.weixin.qq.com/s?__bizMzA5MzI3NjE2MA&mid2650235949&idx1&sn0f7eded67f834d38b02f8872768cb68a&scene0#wechat_redirect今天周二&#xff0c;又該跟大家分享由我執筆的文章了。從之前我寫的deep links、通知欄微技巧這兩篇文章中&a…

【CC精品教程】任務三:CC刺像控點,提交空三,新建重建項目(三維格網、三維點云、DOM和DSM)

《無人機航空攝影測量精品教程》合集目錄(Pix4d、CC、EPS、PhotoScan、Inpho) 【CC精品教程】任務一:CC新建工程、添加照片、相機參數設置、選擇坐標系統 【CC精品教程】任務二:導入像控點、差分POS,空三平差權重設置,提交自由空三 主要任務是準確的刺像控點,提交空三,…

官宣.NET 7 預覽版5

點擊上方藍字關注我們&#xff08;本文閱讀時間&#xff1a;12分鐘)今天我們發布了 .NET 7 預覽版 5。.NET 7 的這個預覽版包括對通用數學的改進&#xff0c;方便了 API 作者&#xff0c;使其更輕松&#xff0c;一個新的 ML.NET 文本分類 API&#xff0c;增加了最先進的深度學習…

[轉]Android產品研發(十九)

轉載請標明出處&#xff1a;一片楓葉的專欄 上一篇文章中我們講解了webview中問題集錦&#xff0c;講解了webview的性能優化、webview種入Cookie信息、activity退出的時候清除webview信息報錯、如何通過java代碼和js代碼相互交互、webview如何下載文件以及騰訊的X5瀏覽服務等知…

C語言試題八十九之實現插入排序算法

??個人主頁:個人主頁 ??系列專欄:C語言試題200例目錄 ??推薦一款刷算法、筆試、面經、拿大公司offer神器 ?? 點擊跳轉進入網站 ?作者簡介:大家好,我是碼莎拉蒂,CSDN博客專家(全站排名Top 50),阿里云博客專家、51CTO博客專家、華為云享專家 1、題目 C語言實現現…

【CC精品教程】ContextCapture 10.17安裝教程(附CC10.17安裝包下載)

《無人機航空攝影測量精品教程》合集目錄(Pix4d、CC、EPS、PhotoScan、Inpho) CC10.17相比之前的版本有了好的新的功能和優點,在傾斜攝影測量中有了更多的優勢,精度和運行速度有了很大的提升。本文講解CC的安裝,附CC10.17安裝包下載,是您航測傾斜攝影測量的入門必備。 文…

centos7 kickstart 使用小結

1、添加參數使網卡名稱變為eth 1bootloader --locationmbr --append"net.ifnames0 biosdevname0 rhgb quiet" 2、psize使用說明&#xff1a;修改vg PE16m 默認4m 支持256G磁盤&#xff0c;適當的調整pesize,可以更多的使用磁盤空間 1volgroup Vol1--pesize16384 pv.…

IOS-網絡(文件上傳)

1 //2 // ViewController.m3 // IOS_0206_文件上傳4 //5 // Created by ma c on 16/2/6.6 // Copyright © 2016年 博文科技. All rights reserved.7 //8 9 #import "ViewController.h"10 #define BWFileBoundary "----------BowenKeJi"11 #define…