一個菜鳥的設計模式之旅,使用 Golang 實現。本節實現裝飾模式。小明和小王去吃沙縣小吃,各自喜歡不同的搭配,需要考慮每個人飲食喜好不同,隨時可能的變化。 ...
一個菜鳥的設計模式之旅,文章可能會有不對的地方,懇請大佬指出錯誤。
編程旅途是漫長遙遠的,在不同時刻有不同的感悟,本文會一直更新下去。
程式介紹
本程式實現裝飾模式。小明和小王去吃沙縣小吃,各自喜歡不同的搭配,需要考慮每個人飲食喜好不同,隨時可能的變化。
小明想吃不帶湯的面
拿個碗裝了麵條加個炸蛋加牛肉片加點醬汁
小王想吃餛飩,還特別愛吃雞腿
拿個碗裝了餛飩加個雞腿加個雞腿加點湯
程式代碼
decorator.go
package main
import "fmt"
type component interface {
operation()
}
type noodle struct{}
type huntun struct{}
func (e noodle) operation() {
fmt.Printf("拿個碗裝了麵條")
}
func (e huntun) operation() {
fmt.Printf("拿個碗裝了餛飩")
}
type decorator struct {
component component
}
func (d *decorator) setComponent(c component) {
d.component = c
}
func (d *decorator) operation() {
if d.component != nil {
d.component.operation()
}
}
type egg struct{ decorator }
type beef struct{ decorator }
type sauce struct{ decorator }
type soup struct{ decorator }
type chicken struct{ decorator }
func (e egg) operation() {
e.decorator.operation()
fmt.Printf("加個炸蛋") // 可以是該結構類型獨有的方法
}
func (e beef) operation() {
e.component.operation()
fmt.Printf("加牛肉片")
}
func (e sauce) operation() {
e.component.operation()
fmt.Printf("加點醬汁")
}
func (e soup) operation() {
e.component.operation()
fmt.Printf("加點湯")
}
func (e chicken) operation() {
e.component.operation()
fmt.Printf("加個雞腿")
}
main.go
package main
import "fmt"
func main() {
fmt.Println("小明想吃不帶湯的面")
noodle := noodle{}
egg := egg{decorator{noodle}}
beef := beef{decorator{egg}}
sauce := sauce{decorator{beef}}
sauce.operation()
/* -------------------------------------------------------------------------- */
fmt.Println("\n小王想吃餛飩,還特別愛吃雞腿")
huntun := huntun{}
chicken1 := chicken{}
chicken2 := chicken{}
soup := soup{}
chicken1.setComponent(huntun)
chicken2.setComponent(chicken1)
soup.setComponent(chicken2)
soup.operation()
}
Console
小明想吃不帶湯的面
拿個碗裝了麵條加個炸蛋加牛肉片加點醬汁
小王想吃餛飩,還特別愛吃雞腿
拿個碗裝了餛飩加個雞腿加個雞腿加點湯
思考總結
什麼是裝飾模式
裝飾器模式(Decorator Pattern)允許向一個現有的對象添加新的功能,同時又不改變其結構。這種類型的設計模式屬於結構型模式,它是作為現有的類的一個包裝。
裝飾模式:動態地給一個對象添加一些額外的職責,就增加功能來說,裝飾模式比生成子類更為靈活。
面對變化,如果採用生成子類的方式進行擴充,為支持每一種擴展的組合,會產生大量的子類。事實上,這些子類多半隻是為某個對象增加一些職責,此時通過裝飾模式,可以更加靈活、動態、透明的方式給單個對象添加職責,在不需要時也可以撤銷相應職責。這種模式創建了一個裝飾類,用來包裝原有的類,併在保持類方法簽名完整性的前提下,提供了額外的功能。
主要解決:一般的,我們為了擴展一個類經常使用繼承方式實現,由於繼承為類引入靜態特征,並且隨著擴展功能的增多,子類會很膨脹。
何時使用:在不想增加很多子類的情況下擴展類。
如何解決:將具體功能職責劃分,同時繼承裝飾者模式。
關鍵代碼: 1、Component 類充當抽象角色,不應該具體實現。 2、修飾類引用和繼承 Component 類,具體擴展類重寫父類方法。
應用實例: 1、孫悟空有 72 變,當他變成"廟宇"後,他的根本還是一隻猴子,但是他又有了廟宇的功能。 2、不論一幅畫有沒有畫框都可以掛在牆上,但是通常都是有畫框的,並且實際上是畫框被掛在牆上。在掛在牆上之前,畫可以被蒙上玻璃,裝到框子里;這時畫、玻璃和畫框形成了一個物體。
優點:裝飾類和被裝飾類可以獨立發展(類的核心職責和裝飾功能相互分開),不會相互耦合,裝飾模式是繼承的一個替代模式,裝飾模式可以動態擴展一個實現類的功能。把類中的裝飾功能從類中搬移去除,這樣簡化原來的類。
缺點:多層裝飾比較複雜。
使用場景: 1、擴展一個類的功能。 2、動態增加功能,動態撤銷。
註意事項:可代替繼承。當系統需要新功能的時候,是向舊的類中添加新的代碼。這些新加的代碼通常裝飾了原有類的核心職責或主要行為。由於在主類或子類中加入了新的欄位、新的方法、新的邏輯,從而增加了主類的複雜度。而加入這些東西僅僅是為了滿足一些只在某種特定情況下才會執行的特殊行為。
靈活變通:如果只有一個ConcreteComponent
類沒有抽象的Component
類,那麼Decorator
類可以是ConreteComponent
的一個子類。如果只有一個ConcreteDecorator
類,那麼就沒有必要單獨建立一個Decorator
類,可以把Decorator
和ConcreateDecorator
的責任合併成一個類。
與建造者模式不同點:建造者模式要求建造過程必須是穩定的,而裝飾模式可以是不固定過程,可以組合出無數種方案。
參考資料
- 《Go語言核心編程》李文塔
- 《Go語言高級編程》柴樹彬、曹春輝
- 《大話設計模式》程傑
- 單例模式 | 菜鳥教程