1 引例
仍然是汉堡的故事,在Golang设计模式-创建型-简单工厂 一文中,我们提到简单工厂的缺点之一是当产品种类较多时,工厂逻辑会变得非常复杂。哪里复杂,我们就分解哪里,这是分治法最朴素的思想,既然工厂逻辑复杂,那我们就把它分解一下吧。
2 工厂方法
2.1 定义
工厂方法通过定义一个工厂基类和产品基类,并派生相应的工厂和产品子类的方式,实现由具体工厂生产具体产品的目标。
2.2 工厂方法三要素
工厂系列的模式(简单工厂、工厂方法,以及我们马上将要介绍的抽象工厂)都有三要素,即产品、工厂和客户端。
2.2.1 产品
与简单工厂相同,抽象产品即为汉堡,我们在此基础上派生出KFC和McDonalds的具体汉堡。
type Hamburger interface {
Deliver()
}
type KfcHamburger struct{}
func (h KfcHamburger) Deliver() {
fmt.Println("This is a hamburger from KFC.\n")
}
type McdonaldsHamburger struct{}
func (h McdonaldsHamburger) Deliver() {
fmt.Println("This is a hamburger from McDonalds.\n")
}
2.2.2 工厂
与简单工厂模式由一个工厂完成所有产品的创建不同,工厂方法定义了一个抽象的工厂基类,并由派生的具体工厂负责对应产品的生产。
type HamburgerFactory interface {
Create() Hamburger
}
type Kfc struct{}
func (f Kfc) Create() Hamburger {
return new(KfcHamburger)
}
type Mcdonalds struct{}
func (f Mcdonalds) Create() Hamburger {
return new(McdonaldsHamburger)
}
2.2.3 客户端
也就是通知工厂生产汉堡的人啦。
func main() {
prefer := getPreferHamburger()
var factory HamburgerFactory
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.Create()
hamburger.Deliver()
}
我们来测试一下吧:
$ go build -o factory_method.bin factory_method.go
$ ll factory_method.bin
-rwxrwxr-x 1 pirlo pirlo 1672879 8月 30 21:39 factory_method.bin*
$ ./factory_method.bin -prefer KFC
This is a hamburger from KFC.
$ ./factory_method.bin -prefer McDonalds
This is a hamburger from McDonalds.
使用类图表示如下:
2.3 工厂方法的优缺点
- 优点
- 工厂类的功能通过继承的方式得到了分解,避免简单工厂逻辑过于复杂的问题;
- 添加新的产品时只需要派生新的工厂和产品子类,而不需要修改原有工厂和产品的逻辑,符合开放-封闭原则。
- 缺点
- 工厂方法虽然分解了工厂逻辑,但客户端却需要参与产品类型的选择,即把原来简单工厂的复杂逻辑部分分担给了客户端。
完整代码:工厂方法