创建型模式-工厂方法
什么是工厂方法
工厂方法是一种创建型设计模式, 其在父类中提供一个创建对象的 方法,允许子类决定实例化对象 的类型

Example
产品接口
1 2 3 4 5 6 7 8
| package main
type IGun interface { setName(name string) setPower(power int) getName() string getPower() int }
|
具体产品A
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| package main
type Gun struct { name string power int }
func (g *Gun) setName(name string) { g.name = name }
func (g *Gun) getName() string { return g.name }
func (g *Gun) setPower(power int) { g.power = power }
func (g *Gun) getPower() int { return g.power }
|
具体产品B
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| package main
type Ak47 struct { Gun }
func newAk47() IGun { return &Ak47{ Gun: Gun{ name: "AK47 gun", power: 4, }, } }
|
具体产品C
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| package main
type musket struct { Gun }
func newMusket() IGun { return &musket{ Gun: Gun{ name: "Musket gun", power: 1, }, } }
|
工厂
1 2 3 4 5 6 7 8 9 10 11 12 13
| package main
import "fmt"
func getGun(gunType string) (IGun, error) { if gunType == "ak47" { return newAk47(), nil } if gunType == "musket" { return newMusket(), nil } return nil, fmt.Errorf("Wrong gun type passed") }
|
客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| package main
import "fmt"
func main() { ak47, _ := getGun("ak47") musket, _ := getGun("musket")
printDetails(ak47) printDetails(musket) }
func printDetails(g IGun) { fmt.Printf("Gun: %s", g.getName()) fmt.Println() fmt.Printf("Power: %d", g.getPower()) fmt.Println() }
|
适用场景
1.当你在编写代码的过程中,如果无法预知对象确切类别及其 依赖关系时,可使用工厂方法。
- 例如,如果需要向应用中添加一种新产品,你只需要开发新 的创建者子类,然后重写其工厂方法即可
- 如果你希望用户能扩展你软件库或框架的内部组件,可使用 工厂方法
- 解决方案是将各框架中构造组件的代码集中到单个工厂方法 中,并在继承该组件之外允许任何人对该方法进行重写
- 如果你希望复用现有对象来节省系统资源,而不是每次都重 新创建对象,可使用工厂方法
优缺点
优点
缺点
- 应用工厂方法模式需要引入许多新的子类,代码可能会因此 变得更复杂。最好的情况是将该模式引入创建者类的现有层 次结构中
与其他模式的关系
- 在许多设计工作的初期都会使用工厂方法(较为简单,而且 可以更方便地通过子类进行定制),随后演化为使用抽象工 厂、原型或生成器(更灵活但更加复杂)
- • 抽象工厂模式通常基于一组工厂方法,但你也可以使用原型 模式来生成这些类的方法
- 你可以同时使用工厂方法和迭代器来让子类集合返回不同类 型的迭代器,并使得迭代器与集合相匹配。
- • 原型并不基于继承,因此没有继承的缺点。另一方面,原型 需要对被复制对象进行复杂的初始化。 工厂方法基于继承, 但是它不需要初始化步骤。
- 工厂方法是模板方法的一种特殊形式。同时,工厂方法可以 作为一个大型模板方法中的一个步骤