Factory Method Pattern(工厂方法模式)
工厂方法模式解决了简单工厂模式的部分缺点。
之所以能够解决这种缺点,是因为工厂方法模式把具体产品(实例)的创建放到了具体的产品工厂去做。
举个例子,现在有一个玩具工厂,在简单工厂模式中,它分别生产拼图和弹珠两种玩具,这两种玩具都是由这个玩具工厂一手创建的。而在工厂方法模式中,相当于玩具工具工厂底下还有两个子工厂,分别是拼图工厂和弹珠工厂,拼图和弹珠两种玩具的创建由这两个子工厂管理。在这种情况下,玩具工厂只是一个接口,包含了New()
方法,而拼图工厂和弹珠工厂都实现了这个接口。
工厂方法模式实现起来,相对于简单工厂模式,使用的代码和对象生成的灵活性大大增加了。
五大要素
来看看工厂方法模式的五大要素:
- 模式名称:工厂方法模式
- 目的(What):定义一个工厂接口创建对象,不同的子类实现这个接口创建各自的对象,创建对象的逻辑由子类实现
- 解决的问题(Why):当我们明确知道不同地条件下需要创建不同的对象时,使用这种模式(与简单工厂模式解决的问题类似,同时解决了简单工厂模式的部分缺点)
- 解决方案(How):实现一个工厂接口,包含了
New()
方法,返回该工厂具体生产的工厂类,不同的子工厂都实现了这个New()
方法,实现了工厂接口,这样就让具体工厂类的创建由各自对应的工厂类工厂实现 - 解决效果:
- 优点:
- 在添加新的工厂类时,不需要更改工厂类逻辑,而是添加新的子工厂类
- 屏蔽产品的具体实现,调用者只关心产品的接口
- 缺点:
- 每次需要新添加一个工厂时,比如现在是玩具厂,需要添加一个针织厂,就需要新建一个工厂对象和一些工厂类对象,使得系统中类的个数成倍在增加,在一定程度上增加了系统的复杂度(这个缺点其实还是存在)
- 优点:
Go实现工厂方法模式
场景
现在有一个玩具厂,我们想要生产一堆玩具,玩具包括拼图(puzzle)和弹珠(marble)。每种玩具都有对应的子玩具厂生产,拼图由拼图厂生产,弹珠由弹珠厂生产。
factory_method.go
:
package factoryMethod
import "fmt"
// 玩具工厂接口
type ToyFactory interface {
New() Toy
}
// 玩具接口,需要实现一个Play方法
type Toy interface {
Play()
}
// 拼图玩具,实现了玩具接口
type Puzzle struct {}
func (*Puzzle) Play() {
fmt.Println("playing puzzle")
}
// 弹珠玩具,实现了玩具接口
type Marble struct {}
func (*Marble) Play() {
fmt.Println("playing marble")
}
// 拼图厂,实现了玩具厂接口
type PuzzleFactory struct {}
func (p *PuzzleFactory) New() Toy {
return new(Puzzle)
}
// 拼图厂,实现了玩具厂接口
type MarbleFactory struct {}
func (p *MarbleFactory) New() Toy {
return new(Marble)
}
simple_factory_test.go
:
package factoryMethod
import "testing"
func TestFactoryMethod(t *testing.T) {
var factory ToyFactory
factory = &PuzzleFactory{}
toy1 := factory.New()
toy1.Play()
factory = &MarbleFactory{}
toy2 := factory.New()
toy2.Play()
}
执行测试结果:
=== RUN TestFactoryMethod
playing puzzle
playing marble
--- PASS: TestFactoryMethod (0.00s)
PASS