1 简介

工厂模式定义了一个用于创建对象的接口,可以让子类决定实例化哪个类。工厂模式是创建对象的最佳方法之一,其中对象创建逻辑也是对客户端隐藏的
image-1689504910809

  • 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 缺点

  • 集成类的数量大幅增加,不同产品类都需要具体工厂
  • 每个实现类都需要完成完成接口类的定义,增加工作量
  • 产品接口增加方法,每个实现类都需要调整
  • 引入抽象层,提高了开发者的心智负担,加大了理解的难度