1 引例
接上文Golang設計模式-創建型-工廠方法 ,有一天,李雷聽說韓梅梅不但喜歡喫漢堡,還喜歡喫雞翅,怎麼辦呢?讓工廠的Create方法既生產漢堡,又生產雞翅嗎?小皮說:不好不好,這違反了“單一職責”原則,生產漢堡與生產雞翅耦合在一起,任何一種方法發生變更都會毫無必要地影響另外一種產品的生產,有沒有更好的辦法呢?當然有,且聽小皮道來…
2 抽象工廠
2.1 定義
抽象工廠在工廠方法的基礎上引入了“產品簇”的概念,簡單理解,工廠方法只生產一種產品,抽象工廠則生產多種產品。
2.2 抽象工廠三元素
2.2.1 產品
抽象工廠與簡單工廠和工廠方法最顯著的差別就是抽象工廠的產品有多種,如引例的漢堡和雞翅。
產品一:漢堡,具體包括肯德基的漢堡和麥當勞的漢堡:
// product type one: hamburger
type Hamburger interface {
Deliver()
}
type KfcHamburger struct{}
func (h KfcHamburger) Deliver() {
fmt.Println("This is a hamburger from KFC.")
}
type McdonaldsHamburger struct{}
func (h McdonaldsHamburger) Deliver() {
fmt.Println("This is a hamburger from McDonalds.")
}
產品二:雞翅,也派生出肯德基和麥當勞的雞翅:
// product type two: chicken wing
type ChickenWing interface {
Deliver()
}
type KfcChickenWing struct{}
func (wing KfcChickenWing) Deliver() {
fmt.Println("This is a chicken wing from KFC.")
}
type McdonaldsChickenWing struct{}
func (wing McdonaldsChickenWing) Deliver() {
fmt.Println("This is a chicken wing from McDonalds.")
}
2.2.2 工廠
抽象工廠需要生產兩張產品,因此我們分別定義生產漢堡和生產雞翅的接口如下:
// abstract factory
type FastFoodFactory interface {
CreateHamburger() Hamburger
CreateChickenWing() ChickenWing
}
具體工廠一:肯德基,負責生產肯德基的漢堡和雞翅:
// concrete factory one: KFC
type Kfc struct{}
func (factory Kfc) CreateHamburger() Hamburger {
return new(KfcHamburger)
}
func (factory Kfc) CreateChickenWing() ChickenWing {
return new(KfcChickenWing)
}
具體工廠二:麥當勞,負責生產麥當勞的漢堡和雞翅:
// concrete factory two: McDonalds
type Mcdonalds struct{}
func (factory Mcdonalds) CreateHamburger() Hamburger {
return new(McdonaldsHamburger)
}
func (factory Mcdonalds) CreateChickenWing() ChickenWing {
return new(McdonaldsChickenWing)
}
2.2.3 客戶端
抽象工廠的客戶端與工廠方法幾乎沒有差別,僅需要指定工廠類型,就可以得到最終想要的具體產品,只不過這一次的產品種類更多而已:
func main() {
prefer := GetPreferredFastFood()
var factory FastFoodFactory
switch prefer {
case "KFC":
factory = new(Kfc)
case "McDonalds":
factory = new(Mcdonalds)
default:
fmt.Printf("%s not supported yet.\n", prefer)
os.Exit(1)
}
hamburger := factory.CreateHamburger()
chickenWing := factory.CreateChickenWing()
hamburger.Deliver()
chickenWing.Deliver()
}
我們測試一下:
$ go build -o abstract_factory.bin abstract_factory.go
$ ll abstract_factory.bin
-rwxrwxr-x 1 pirlo pirlo 1681701 9月 2 22:12 abstract_factory.bin*
$ ./abstract_factory.bin -prefer KFC
This is a hamburger from KFC.
This is a chicken wing from KFC.
$ ./abstract_factory.bin -prefer KFC
This is a hamburger from KFC.
This is a chicken wing from KFC.
使用類圖表示如下:
2.3 抽象工廠的優缺點
- 優點
- 與簡單工廠和工廠方法相比,抽象工廠可以生產更多種類的產品,即產品形態更加多樣化
- 不同種類的產品之間完全解耦,添加新產品時對已有產品實現沒有任何影響,即符合“開放-封閉”原則
缺點
- 相比工廠方法,抽象工廠模式的繼承關係更多,增加了系統的複雜性
- 添加新產品時,除了新增產品的繼承關係外,還需要修改工廠基類和所有子類的邏輯,客戶端也需要做相應適配,增加了系統擴展的難度。
完整代碼:抽象工廠