1 简介
工厂模式定义了一个用于创建对象的接口,可以让子类决定实例化哪个类。工厂模式是创建对象的最佳方法之一,其中对象创建逻辑也是对客户端隐藏的
- Factory:声明返回产品对象的工厂方法的接口
- ConcreteFactory:实现工厂接口的类
- Product:声明产品的接口
- ConcreteProduct:实现产品接口的类
2 使用场景
- 无法预知对象的具体类型和依赖关系
- 提供可以扩展软件或框架的内部组件
- 一个类需要通过子类指定其创建的对象
3 实现
3.1 使用逻辑
// Factory 工厂接口
type Factory interface {
FactoryMethod(owner string) Product
}
// ConcreteFactory 工厂类
type ConcreteFactory struct {
}
// FactoryMethod 工厂接口实现
func (c *ConcreteFactory) FactoryMethod(owner string) Product {
return &ConcreteProduct{owner: owner}
}
// Product 产品接口
type Product interface {
User()
}
// ConcreteProduct 产品类
type ConcreteProduct struct {
owner string
}
func (c *ConcreteProduct) User() {
fmt.Println("This is a concrete product - " + c.owner)
}
func main() {
f := ConcreteFactory{}
p := f.FactoryMethod("aaa")
p.User()
}
// Out: This is a concrete product - aaa
3.2 实现
以口袋妖怪为例
接口
// PocketMonster 口袋妖怪接口
type PocketMonster interface {
SetSkill(skill string)
GetName() string
GetSkill() string
}
实现接口
// Pikachu 皮卡丘
type Pikachu struct {
name string
skill string
}
func NewPikachu() PocketMonster {
return &Pikachu{name: "皮卡丘"}
}
func (p *Pikachu) SetSkill(skill string) {
p.skill = skill
}
func (p *Pikachu) GetName() string {
return p.name
}
func (p *Pikachu) GetSkill() string {
return p.skill
}
// Charizard 喷火龙
type Charizard struct {
name string
skill string
}
func NewCharizard() PocketMonster {
return &Charizard{name: "喷火龙"}
}
func (p *Charizard) SetSkill(skill string) {
p.skill = skill
}
func (p *Charizard) GetName() string {
return p.name
}
func (p *Charizard) GetSkill() string {
return p.skill
}
工厂
// PocketMonsterFactory 工厂
type PocketMonsterFactory struct {
}
func (f *PocketMonsterFactory) Get(name string) (PocketMonster, bool) {
switch name {
case "Pikachu":
return NewPikachu(), true
case "Charizard":
return NewCharizard(), true
default:
return nil, false
}
}
使用
func main() {
// 初始化工厂
f := &PocketMonsterFactory{}
// 使用工厂
pcM, ok := f.Get("Pikachu")
pcM.SetSkill("十万伏特")
if ok {
fmt.Printf("%s 使用了 %s\n", pcM.GetName(), pcM.GetSkill())
}
czM, ok := f.Get("Charizard")
czM.SetSkill("喷射火焰")
if ok {
fmt.Printf("%s 使用了 %s\n", czM.GetName(), czM.GetSkill())
}
// Out:
// 皮卡丘 使用了 十万伏特
// 喷火龙 使用了 喷射火焰
}
4 优缺点分析
4.1 优点
- 可以提供稳定的可扩展性
- 组件可以单独测试
- 组件统一化、规范化
4.2 缺点
- 集成类的数量大幅增加,不同产品类都需要具体工厂
- 每个实现类都需要完成完成接口类的定义,增加工作量
- 产品接口增加方法,每个实现类都需要调整
- 引入抽象层,提高了开发者的心智负担,加大了理解的难度