第十一章:組合模式

一、情景

Tony作為一名合格軟件工程師要學(xué)會組裝一臺自己的電腦济蝉。一臺電腦的組成:主板杰刽、電源,而主板上又有CPU王滤、硬盤贺嫂、顯卡。顯示器需要單獨插電源才能工作雁乡。

程序模擬場景

package main

import "fmt"

/********************************基礎(chǔ)組件**********************************************/

type ComputerComponent struct {
    name string
}

func (c *ComputerComponent) isComposite() bool {
    return false
}

func (c *ComputerComponent)startUp(indent string){
    fmt.Printf("%s%s準(zhǔn)備開始工作...\n",indent, c.name)
}

func (c *ComputerComponent)shutdown(indent string){
    fmt.Printf("%s%s即將結(jié)束工作...\n", indent,c.name)
}

func NewComponent(name string)*ComputerComponent{
    return &ComputerComponent{
        name: name,
    }
}

/********************************實際組件**********************************************/

type CPU struct {
    /*處理器*/
    *ComputerComponent
}

func (c *CPU)showInfo(indent string){
    fmt.Printf("%sCPU:%s, 可以進行高速計算第喳。\n",indent, c.name)
}

func NewCpu(name string) *CPU{
    return &CPU{
        ComputerComponent:NewComponent(name),
    }
}

type MemoryCard struct {
    /*內(nèi)存*/
    *ComputerComponent
}

func NewMemory(name string) *MemoryCard {
    return &MemoryCard{
        ComputerComponent:NewComponent(name),
    }
}

func (m *MemoryCard)showInfo(indent string){
    fmt.Printf("%s內(nèi)存:%s,可以緩存數(shù)據(jù),讀寫速度塊蔗怠。\n", indent, m.name)
}

type HardDisk struct {
    /*硬盤*/
    *ComputerComponent
}

func (h *HardDisk)showInfo(indent string){
    fmt.Printf("%s硬盤:%s,可以永久存儲數(shù)據(jù)墩弯,容量大吩跋。\n",indent,h.name)
}

func NewHardDisk(name string) *HardDisk{
    return &HardDisk{
        ComputerComponent:NewComponent(name),
    }
}

type GraphicsCard struct {
    /*顯卡*/
    *ComputerComponent
}

func (g *GraphicsCard)showInfo(indent string){
    fmt.Printf("%s顯卡:%s寞射,可以高速計算和處理圖形圖像。\n",indent,g.name)
}

func NewGraphics(name string)* GraphicsCard{
    return &GraphicsCard{
        ComputerComponent:NewComponent(name),
    }
}

type Battery struct {
    /*電源*/
    *ComputerComponent
}

func (b *Battery)showInfo(indent string){
    fmt.Printf("%s電源:%s锌钮,可以持續(xù)給主板和外接配件供電桥温。\n",indent)
}

func NewBattery(name string) *Battery {
    return &Battery{
        ComputerComponent:NewComponent(name),
    }
}

type Fan struct {
    /*風(fēng)扇*/
    *ComputerComponent
}

func (f *Fan)showInfo(indent string){
    fmt.Printf("%s風(fēng)扇:%s,輔助CPU散熱梁丘。\n",indent,f.name)
}

func NewFan(name string)*Fan{
    return &Fan{
        ComputerComponent:NewComponent(name),
    }
}

type DisPlayer struct {
    /*顯示器*/
    *ComputerComponent
}

func (d *DisPlayer)showInfo(indent string){
    fmt.Printf("%s顯示器:%s侵浸,負(fù)責(zé)內(nèi)容的顯示。\n",indent,d.name)
}

func NewDisPlayer(name string) *DisPlayer {
    return &DisPlayer{
        ComputerComponent:NewComponent(name),
    }
}

/**********************************抽象組件********************************************/

type Part interface {
    showInfo(indent string)
    startUp(indent string)
    shutdown(indent string)
}

/***********************************配件組合器*******************************************/

type ComputerComposite struct {
    /*配件組合器*/
    *ComputerComponent
    Components []Part
}

func (c *ComputerComposite)showInfo(indent string){
    fmt.Printf("%s氛谜,由以下部件組成:\n", c.name)
    indent += "\t"
    for i:=0;i<len(c.Components);i++{
        c.Components[i].showInfo(indent)
    }
}

func (c *ComputerComposite)isComposite()bool{
    return true
}

func (c *ComputerComposite) addComponent(component Part) {
    c.Components = append(c.Components, component)
}

func (c *ComputerComposite)startUp(indent string){
    c.ComputerComponent.startUp(indent)
    indent += "\t"
    for i:=0;i<len(c.Components);i++{
        c.Components[i].startUp(indent)
    }
}

func (c *ComputerComposite)shutdown(indent string){
    c.ComputerComponent.shutdown(indent)
    indent += "\t"
    for i:=0; i<len(c.Components);i++{
        c.Components[i].shutdown(indent)
    }
}

func NewComposite(name string) *ComputerComposite{
    return &ComputerComposite{
        ComputerComponent:NewComponent(name),
    }
}

/*******************************組裝組件************************************************/

type MainBoard struct {
    /*主板*/
    *ComputerComposite
}

func (m *MainBoard)showInfo(indent string){
    fmt.Printf(indent + "主板:")
    m.ComputerComposite.showInfo(indent)
}

func NewMainBoard(name string)*MainBoard{
    return &MainBoard{
        ComputerComposite:NewComposite(name),
    }
}

type ComputerCase struct {
    /*機箱*/
    *ComputerComposite
}

func (c *ComputerCase)showInfo(indent string){
    fmt.Printf(indent+"機箱:")
    c.ComputerComposite.showInfo(indent)
}

func NewComputerCase(name string)*ComputerCase{
    return &ComputerCase{
        ComputerComposite:NewComposite(name),
    }
}

/********************************電腦整機**********************************************/

type Computer struct {
    /*電腦*/
    *ComputerComposite
}

func (c *Computer)showInfo(indent string){
    fmt.Printf(indent + "電腦:")
    c.ComputerComposite.showInfo(indent)
}

func NewComputer(name string)*Computer{
    return &Computer{
        NewComposite(name),
    }
}


func testComputer(){

    mainBoard := NewMainBoard("GIGABYTE Z170M M-atx")
    cpu := NewCpu("Intel core I5-6600k")
    memoryCard := NewMemory("Kingston Fury DDR4")
    hardDisk := NewHardDisk("Kingston v300")
    graphicsCard := NewGraphics("Colorful iGame750")
    mainBoard.addComponent(cpu)
    mainBoard.addComponent(memoryCard)
    mainBoard.addComponent(hardDisk)
    mainBoard.addComponent(graphicsCard)

    battery := NewBattery("Antec vp 450p")
    fan := NewFan("DEEPCOOL 120T")
    computerCase := NewComputerCase("SAMA MATX")
    computerCase.addComponent(mainBoard)
    computerCase.addComponent(battery)
    computerCase.addComponent(fan)

    disPlayer := NewDisPlayer("AOC Lv243xip")
    computer := NewComputer("Tony DIY 電腦")
    computer.addComponent(computerCase)
    computer.addComponent(disPlayer)

    computer.showInfo("")
    fmt.Printf("\n開機過程:\n")
    computer.startUp("")
    fmt.Printf("\n關(guān)機過程:\n")
    computer.shutdown("")
}

func main()  {
    testComputer()
}


輸出結(jié)果:

電腦:Tony DIY 電腦掏觉,由以下部件組成:
    機箱:SAMA MATX,由以下部件組成:
        主板:GIGABYTE Z170M M-atx值漫,由以下部件組成:
            CPU:Intel core I5-6600k, 可以進行高速計算澳腹。
            內(nèi)存:Kingston Fury DDR4,可以緩存數(shù)據(jù),讀寫速度塊。
            硬盤:Kingston v300,可以永久存儲數(shù)據(jù)酱塔,容量大沥邻。
            顯卡:Colorful iGame750,可以高速計算和處理圖形圖像羊娃。
        電源:%!s(MISSING)唐全,可以持續(xù)給主板和外接配件供電。
        風(fēng)扇:DEEPCOOL 120T蕊玷,輔助CPU散熱邮利。
    顯示器:AOC Lv243xip,負(fù)責(zé)內(nèi)容的顯示集畅。

開機過程:
Tony DIY 電腦準(zhǔn)備開始工作...
    SAMA MATX準(zhǔn)備開始工作...
        GIGABYTE Z170M M-atx準(zhǔn)備開始工作...
            Intel core I5-6600k準(zhǔn)備開始工作...
            Kingston Fury DDR4準(zhǔn)備開始工作...
            Kingston v300準(zhǔn)備開始工作...
            Colorful iGame750準(zhǔn)備開始工作...
        Antec vp 450p準(zhǔn)備開始工作...
        DEEPCOOL 120T準(zhǔn)備開始工作...
    AOC Lv243xip準(zhǔn)備開始工作...

關(guān)機過程:
Tony DIY 電腦即將結(jié)束工作...
    SAMA MATX即將結(jié)束工作...
        GIGABYTE Z170M M-atx即將結(jié)束工作...
            Intel core I5-6600k即將結(jié)束工作...
            Kingston Fury DDR4即將結(jié)束工作...
            Kingston v300即將結(jié)束工作...
            Colorful iGame750即將結(jié)束工作...
        Antec vp 450p即將結(jié)束工作...
        DEEPCOOL 120T即將結(jié)束工作...
    AOC Lv243xip即將結(jié)束工作...

Process finished with exit code 0

二近弟、從劇情中思考什么是組合模式

2.1什么是組合模式

將對象組合成樹形結(jié)構(gòu)以表示“整體-部分”的層次結(jié)構(gòu)關(guān)系。組合使得用戶對單個對象和復(fù)合對象的使用具有一致性挺智。
組合模式使得用戶對單個對象和組合對象的使用具有一致性(如源碼示例中 startup與shutdown的使用)祷愉,使用組合對象就像使用一般對象一樣,不用關(guān)心內(nèi)部的組織結(jié)構(gòu)赦颇。

2.2組合模式的設(shè)計思想

Tony自己DIY組裝的電腦是由各個配件組成的二鳄,在組裝之前,就是單個CPU媒怯、硬盤订讼、顯卡等配件,不能稱為電腦扇苞,只有把它們按正確的方式組裝在一起欺殿,配合操作系統(tǒng)才能正常運行。一般人使用電腦并不會關(guān)注內(nèi)部的結(jié)構(gòu)鳖敷,只會關(guān)注一臺整機脖苏。
組裝的電腦具有明顯的部分與整體的關(guān)系,主板定踱、電源等是電腦的一部分棍潘,而主板上又有CPU、硬盤崖媚、顯卡亦歉,它們又是主板的一部分。像電腦一樣畅哑,把對象組合成樹形結(jié)構(gòu)肴楷,以表示“部分-整體”的層次結(jié)構(gòu)的程序設(shè)計模式就叫組合模式

臺式機的組成.png

我們將這種層次關(guān)系轉(zhuǎn)換成對象的組合關(guān)系荠呐,如下圖
組合關(guān)系.png

三赛蔫、模型抽象

組合模式的類圖.png

Component是組件的基類绷杜,定義統(tǒng)一的方法feature()和isComposite(),isComposite()用于判斷一個組件是否為復(fù)合組件。ComponentImplA 和 ComponentImplB 是具體的組件濒募。Composite就是復(fù)合組件(也就是組合對象)鞭盟,復(fù)合組件可以添加或刪除組件,CompositeImplA 和CompositeImplB是具體的復(fù)合組件瑰剃。復(fù)合組件本身也是一個組件齿诉,因此組合對象可以像一般對象一樣被使用,因為它也實現(xiàn)了Component的feature()方法晌姚。

3.1模型說明

1.設(shè)計要點
在設(shè)計迭代器模式時粤剧,要注意以下兩點:
(1)理清部分與整體的關(guān)系,了解對象的組成結(jié)構(gòu)挥唠。
(2)組合模式是一種具有層次關(guān)系的樹形結(jié)構(gòu)抵恋,不能再分的葉子節(jié)點是具體的組件,也就是最小的邏輯單元宝磨;具有子節(jié)點(由多個子組件組成)的組件稱為復(fù)合組件弧关,也就是組合對象。
2.組合模式的優(yōu)缺點
優(yōu)點:
(1)調(diào)用簡單唤锉,組合對象可以像一般對象一樣使用世囊。
(2)組合對象可以自由地增加、刪除組件窿祥,可靈活地組合不同的對象株憾。
缺點:
在一些層次結(jié)構(gòu)太深的場景中,組合結(jié)構(gòu)會變得太龐雜晒衩。

四嗤瞎、應(yīng)用場景

  1. 對象之間具有明顯的“部分-整體”的關(guān)系時,或者具有層次關(guān)系時听系。
  2. 組合對象與單個對象具有相同或者類似行為(方法)贝奇,用戶希望統(tǒng)一地使用組合結(jié)構(gòu)中的所有對象
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市跛锌,隨后出現(xiàn)的幾起案子弃秆,更是在濱河造成了極大的恐慌届惋,老刑警劉巖髓帽,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異脑豹,居然都是意外死亡郑藏,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進店門瘩欺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來必盖,“玉大人拌牲,你說我怎么就攤上這事「柚啵” “怎么了塌忽?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長失驶。 經(jīng)常有香客問我土居,道長,這世上最難降的妖魔是什么嬉探? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任擦耀,我火速辦了婚禮,結(jié)果婚禮上涩堤,老公的妹妹穿的比我還像新娘眷蜓。我一直安慰自己,他們只是感情好胎围,可當(dāng)我...
    茶點故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布吁系。 她就那樣靜靜地躺著,像睡著了一般白魂。 火紅的嫁衣襯著肌膚如雪垮抗。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天碧聪,我揣著相機與錄音冒版,去河邊找鬼。 笑死逞姿,一個胖子當(dāng)著我的面吹牛辞嗡,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播滞造,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼续室,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了谒养?” 一聲冷哼從身側(cè)響起挺狰,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎买窟,沒想到半個月后丰泊,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡始绍,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年瞳购,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片亏推。...
    茶點故事閱讀 38,094評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡学赛,死狀恐怖年堆,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情盏浇,我是刑警寧澤变丧,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站绢掰,受9級特大地震影響锄贷,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜曼月,卻給世界環(huán)境...
    茶點故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一谊却、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧哑芹,春花似錦炎辨、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至末购,卻和暖如春破喻,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背盟榴。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工曹质, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人擎场。 一個月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓羽德,卻偏偏與公主長得像,于是被迫代替她去往敵國和親迅办。 傳聞我的和親對象是個殘疾皇子宅静,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,828評論 2 345