設(shè)置
  • 日夜間
    隨系統(tǒng)
    淺色
    深色
  • 主題色

Go 語言學(xué)習(xí):組合,一個對數(shù)據(jù)結(jié)構(gòu)算法和職場都有提升的設(shè)計模式

網(wǎng)管叨bi叨 2023/1/20 13:01:11 責(zé)編:夢澤

大家好,我是每周在這里陪你進步的網(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之家所有文章均包含本聲明。

相關(guān)文章

關(guān)鍵詞:Go語言設(shè)計模式

軟媒旗下網(wǎng)站: IT之家 最會買 - 返利返現(xiàn)優(yōu)惠券 iPhone之家 Win7之家 Win10之家 Win11之家

軟媒旗下軟件: 軟媒手機APP應(yīng)用 魔方 最會買 要知