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 简单工厂的优缺点
- 优点
- 客户端不关注产品的创建过程,避免客户端逻辑的复杂;
- 利于扩展新产品,且无需修改客户端代码。
- 缺点
- 当产品种类较多时,工厂逻辑会变得非常复杂;
- 虽然新增产品时不需要修改客户端实现,但仍然需要对工厂逻辑做调整,实际也不完全符合“开放-封闭”原则。
完整代码: 简单工厂
本文介绍简单工厂模式的应用,通过一个汉堡订购的例子展示了如何利用简单工厂模式来减少客户端代码的复杂性,使产品创建过程更加灵活。

2309

被折叠的 条评论
为什么被折叠?



