1 引例
李雷喜歡上了韓梅梅,他知道韓梅梅喜歡喫漢堡,於是就想買漢堡給她喫,但李雷不確定韓梅梅喜歡的是肯德基的漢堡還是麥當勞的漢堡,怎樣幫助他呢?
最直觀和最簡單的實現就是if+else:
if prefer == "KFC" {
CreateKfcHamburger()
} else if prefer == "McDonalds" {
CreateMcdonaldsHamburger()
}
這個實現的問題是客戶端關注了產品(漢堡)創建的全過程,且當擴展產品種類時需要修改客戶端代碼,違反了開放-封閉原則(對增加開放,對修改封閉)。
那麼有沒有更好的實現呢?
2 簡單工廠
2.1 定義
簡單工廠通過定義一個工廠類,並提供創建產品的方法,將客戶端從創建具體產品的尷尬局面中擺脫出來,客戶端只需要告知產品類型即可,產品的具體創建由工廠完成。
2.2 簡單工廠三要素
- 產品: 客戶端需要的產品
- 工廠: 生產產品的工廠
- 客戶端: 消費產品的客戶
以引例的漢堡工廠爲例,產品即爲漢堡,這個是一個抽象類型,根據產品類型的不同,我們分別定義兩個具體產品,即肯德基的漢堡和麥當勞的漢堡:
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.")
}
漢堡工廠則根據需要生產指定類型的漢堡:
type HamburgerFactory struct{}
func (f HamburgerFactory) CreateHamburger(prefer string) Hamburger {
switch prefer {
case "KFC":
return new(KfcHamburger)
case "McDonalds":
return new(McdonaldsHamburger)
default:
return nil
}
}
於是,客戶端再也不關注產品的具體創建過程了,而是告訴工廠“我需要什麼,你就給我生產什麼”:
func main() {
prefer := getPreferHamburger()
factory := new(creational.HamburgerFactory)
hamburger := factory.CreateHamburger(prefer)
if hamburger == nil {
fmt.Printf("%s not supported yet.\n", prefer)
os.Exit(1)
}
hamburger.Deliver()
}
李雷作爲客戶,只需要獲取韓梅梅喜歡的漢堡類型,然後讓工廠生產就可以了:
$ ./simple_factory.bin -prefer KFC
This is a hamburger from KFC.
$ ./simple_factory.bin -prefer McDonalds
This is a hamburger from McDonalds.
使用類圖表示如下:
2.3 簡單工廠的優缺點
- 優點
- 客戶端不關注產品的創建過程,避免客戶端邏輯的複雜;
- 利於擴展新產品,且無需修改客戶端代碼。
- 缺點
- 當產品種類較多時,工廠邏輯會變得非常複雜;
- 雖然新增產品時不需要修改客戶端實現,但仍然需要對工廠邏輯做調整,實際也不完全符合“開放-封閉”原則。
完整代碼: 簡單工廠