大家好,我是每周在這里陪你進步的網(wǎng)管~,這次我們繼續(xù)設(shè)計模式的學(xué)習(xí)之旅。本次要學(xué)習(xí)的是組合模式,這個模式呢,平時要做業(yè)務(wù)開發(fā)的話并不是很常用,但是對一些特定數(shù)據(jù)結(jié)構(gòu)的處理上卻是少不了它的應(yīng)用。
同時理解了組合模式的原理后對你的數(shù)據(jù)結(jié)構(gòu)和算法的提升也是有幫助的,更重要的是能讓你明白一些職場的道理,具體是啥道理呢?看完文章你就明白啦??。
什么是組合模式
組合模式(Composite Pattern)又叫作部分-整體(Part-Whole)模式,它的宗旨是通過將單個對象(葉子節(jié)點)和組合對象(樹枝節(jié)點)用相同的接口進行表示,使得客戶對單個對象和組合對象的使用具有一致性,屬于結(jié)構(gòu)型設(shè)計模式。
應(yīng)用場景
組合模式的使用要求業(yè)務(wù)場景中的實體必須能夠表示成樹形結(jié)構(gòu)才行,由組合模式將一組對象組織成樹形結(jié)構(gòu),客戶端(代碼的使用者)可以將單個對象和組合對象都看做樹中的節(jié)點,以統(tǒng)一處理邏輯,并且利用樹形結(jié)構(gòu)的特點,將對樹、子樹的處理轉(zhuǎn)化成葉節(jié)點的遞歸處理,依次簡化代碼實現(xiàn)。
通過上邊的描述我們可以馬上想到文件系統(tǒng)、公司組織架構(gòu)這些有層級結(jié)構(gòu)的事物的操作會更適合應(yīng)用組合模式。
組合模式的結(jié)構(gòu)
組合模式由以下幾個角色構(gòu)成:
組件 (Component): 組件是一個接口,描述了樹中單個對象和組合對象都要實現(xiàn)的的操作。
葉節(jié)點 (Leaf) :即單個對象節(jié)點,是樹的基本結(jié)構(gòu),它不包含子節(jié)點,因此也就無法將工作指派給下去,葉節(jié)點最終會完成大部分的實際工作。
組合對象 (Composite)”—— 是包含葉節(jié)點或其他組合對象等子項目的符合對象。組合對象不知道其子項目所屬的具體類,它只通過通用的組件接口與其子項目交互。
客戶端 (Client): 通過組件接口與所有項目交互。因此,客戶端能以相同方式與樹狀結(jié)構(gòu)中的簡單或復(fù)雜對象進行交互。
組合模式代碼實現(xiàn)
下面用一個公司組織架構(gòu)的例子來演示下用代碼怎么實現(xiàn)組合模式。
我們都知道大公司的組織架構(gòu)會很復(fù)雜,往往是由集團總公司--> 分公司,每個層級的公司還有不同的部門,比如說總公司有財務(wù)部,分公司也會有。分公司偏傳統(tǒng)一點,在互聯(lián)網(wǎng)大廠有可能會按 BG、BU 這樣分,不過在展示層級結(jié)構(gòu)上意思都一樣。
咱們來看下這個例子,使用的是 Go 語言的代碼來實現(xiàn)組合模式。首先我們定義一個組織的行為接口,這個接口大到總公司小到一個部門都得實現(xiàn):
// 表示組織機構(gòu)的接口 type Organization interface { display() duty() }
這里為了簡單演示,接口里就提供兩個方法,一個是打印出自己的組織結(jié)構(gòu)的方法 display () 另外一個是展示組織職責(zé)的方法 duty ()。接下來定義和實現(xiàn)組合對象的行為:
// 組合對象--上級部門 "本文使用的完整可運行源碼 去公眾號「網(wǎng)管叨bi叨」發(fā)送【設(shè)計模式】即可領(lǐng)取" type CompositeOrganization struct { orgName string depth int list []Organization } func NewCompositeOrganization(name string, depth int) *CompositeOrganization { return &CompositeOrganization{name, depth, []Organization{}} } func (c *CompositeOrganization) add(org Organization) { if c == nil { return } c.list = end(c.list, org) } func (c *CompositeOrganization) remove(org Organization) { if c == nil { return } for i, val := range c.list { if val == org { c.list = end(c.list[:i], c.list[i+1:]...) return } } return } func (c *CompositeOrganization) display() { if c == nil { return } fmt.Println(strings.Repeat("-", c.depth * 2), " ", c.orgName) for _, val := range c.list { val.display() } } func (c *CompositeOrganization) duty() { if c == nil { return } for _, val := range c.list { val.duty() } }
組合對象用來表示有下屬部門的組織,在代碼里可以看到,它持有一個 [] Organization 類型的列表,這里存放的是它的下屬組織。組合對象的 display、duty 這兩個方法的實現(xiàn)完全就是把工作委托給他們的下屬組織來做的,這也是組合模式的特點。
下面我們再來看兩個職能部門人力資源和財務(wù)部門的類型實現(xiàn)。
// Leaf對象--人力資源部門 "本文使用的完整可運行源碼 去公眾號「網(wǎng)管叨bi叨」發(fā)送【設(shè)計模式】即可領(lǐng)取" type HRDOrg struct { orgName string depth int } func (o *HRDOrg) display() { if o == nil { return } fmt.Println(strings.Repeat("-", o.depth * 2), " ", o.orgName) } func (o *HRDOrg) duty() { if o == nil { return } fmt.Println(o.orgName, "員工招聘培訓(xùn)管理") } // Leaf對象--財務(wù)部門 type FinanceOrg struct { orgName string depth int } func (f *FinanceOrg) display() { if f == nil { return } fmt.Println(strings.Repeat("-", f.depth * 2), " ", f.orgName) } func (f *FinanceOrg) duty() { if f == nil { return } fmt.Println(f.orgName, "員工招聘培訓(xùn)管理") }
只要我們在客戶端中組合好組織架構(gòu)的結(jié)構(gòu),不管有幾層組織,客戶端對整個組織的調(diào)用是不會改變的。
func main() { root := NewCompositeOrganization("北京總公司", 1) root.add(&HRDOrg{orgName: "總公司人力資源部", depth: 2}) root.add(&FinanceOrg{orgName: "總公司財務(wù)部", depth: 2}) compSh := NewCompositeOrganization("上海分公司", 2) compSh.add(&HRDOrg{orgName: "上海分公司人力資源部", depth: 3}) compSh.add(&FinanceOrg{orgName: "上海分公司財務(wù)部", depth: 3}) root.add(compSh) compGd := NewCompositeOrganization("廣東分公司", 2) compGd.add(&HRDOrg{orgName: "廣東分公司人力資源部", depth: 3}) compGd.add(&FinanceOrg{orgName: "南京辦事處財務(wù)部", depth: 3}) root.add(compGd) fmt.Println("公司組織架構(gòu):") root.display() fmt.Println("各組織的職責(zé):") root.duty() }
組合模式和上一節(jié)我們學(xué)的裝飾器模式在結(jié)構(gòu)上挺像的,下面我們來說說他們的區(qū)別。
組合和裝飾器的區(qū)別
組合模式和裝飾器模式在結(jié)構(gòu)上很像,擁有非常相似的類結(jié)構(gòu)(相似到組合模式的類圖就是我 Copy 裝飾器模式改了下方法名字......)。但是兩者在使用意圖上是有區(qū)別的。
組合模式:為葉子對象和組合對象提供了統(tǒng)一的接口,葉子對象分擔(dān)組合對象要做的工作。其實組合對象就是派了下活兒,等下面的干完后,它再給上層調(diào)用者返(匯)回(報),類似于公司里的那些組合 *。
裝飾器模式:裝飾器屬于大哥帶小弟的類型,核心的活兒是小弟干的(小弟就是被裝飾的對象)但是各位大哥會幫你做好干活兒之外的事兒,比如公司你在公司里的 Mentor、項目經(jīng)理、領(lǐng)導(dǎo)們干的事兒就是給在給你做增強,你可以把他們理解成是你的裝飾器??。
說點題外話,如果你的 Mentor、領(lǐng)導(dǎo)沒有給你做增強,那當(dāng)初他們給你定級 P7 是高于你面試的水平的。是希望進來后你能夠拼一把,快速成長起來。P7 這個層級,不是把事情做好就可以的。你需要有體系化思考的能力,它的價值點在哪里,你是否做出了壁壘形成了核心競爭力,是否沉淀了一套可復(fù)用的物理資料和方法論?...... (字兒太多了,完整版請自行搜索)
總結(jié)
組合模式的優(yōu)點主要有以下兩點
實現(xiàn)類似樹形結(jié)構(gòu),可以清楚地定義各層次的復(fù)雜對象,表示對象的全部或部分層次。
簡化了客戶端代碼,讓客戶端忽略了層次的差異,方便對整個層次結(jié)構(gòu)進行控制。
實際上,組合模式與其說是一種設(shè)計模式,倒不如說是對業(yè)務(wù)場景的一種數(shù)據(jù)結(jié)構(gòu)和算法的抽象,場景中的數(shù)據(jù)可以表示成樹這種結(jié)構(gòu),業(yè)務(wù)需求的邏輯可以通過對樹的遞歸遍歷算法實現(xiàn)。
本文來自微信公眾號:網(wǎng)管叨 bi 叨 (ID:kevin_tech),作者:KevinYan11
廣告聲明:文內(nèi)含有的對外跳轉(zhuǎn)鏈接(包括不限于超鏈接、二維碼、口令等形式),用于傳遞更多信息,節(jié)省甄選時間,結(jié)果僅供參考,IT之家所有文章均包含本聲明。