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