go设计模式之工厂方法模式

发布于:2024-04-25 ⋅ 阅读:(17) ⋅ 点赞:(0)

工厂方法模式

什么是工厂方法模式

工厂方法模式是一种创建型设计模式,它定义了一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化推迟到其子类。

这个接口就是工厂接口,子类就是具体工厂类,而需要创建的对象就是产品对象。客户端代码只需要调用工厂接口的方法,而无需关心具体的产品对象是如何创建的。

用于创建对象的过程中将实例化的逻辑封装在一个工厂方法中。

把被创建的对象称为“产品”,把创建产品的对象称为“工厂”。

在 Go 语言中,工厂方法模式经常被用于对象的创建和初始化。

工厂方法模式的主要优点有:

  • 用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程(对创建过程复杂的对象很有作用);

  • 在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类,无须对原工厂进行任何修改,满足开闭原则;

其缺点是:每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度。

角色

工厂方法模式包含四个主要角色:

  • 抽象产品类(Product)
  • 具体产品类(ConcreteProduct)
  • 抽象工厂接口(Factory)
  • 具体工厂类(ConcreteFactory)

抽象产品类定义了产品的接口。

具体产品类实现了具体的产品逻辑。

抽象工厂类定义了创建产品的接口。

具体工厂类实现了具体的产品创建逻辑。

工厂方法代码

工厂方法模式举例

场景:

创建狗子的案例:
创建狗子的接口工厂(接口MakeDogs)
创建狗子具体工厂(实现上面的接口)
狗子接口(sleep()、run())
泰迪、柴犬(具体的狗子)

抽象产品类:

type IDog interface {
	Sleep()
	Run()
}

具体产品类:

柴犬:

// 柴犬
type ChaiDog struct {
}

func (c ChaiDog) Sleep() {
	fmt.Println("睡觉")
}

func (c ChaiDog) Run() {
	fmt.Println("奔跑")
}

泰迪:

// 泰迪
type Teddy struct {
}

func (t Teddy) Sleep() {
	fmt.Println("睡觉")
}

func (t Teddy) Run() {
	fmt.Println("奔跑")
}

抽象工厂类(接口工厂):

创建狗子的抽象接口

type IDogFactory interface {
	MakeDogs(dogType string) IDog
}

具体工厂类:

type DogFactory struct {
}

// 工厂方法,这是一个特殊的方法,用来创建不同的狗子
func (d DogFactory) MakeDogs(dogType string) IDog {
	if dogType == "teddy" {
		return &Teddy{}
	}
	if dogType == "chaidog" {
		return &ChaiDog{}
	}
	return nil
}

场景类:

func main() {
	factory := &DogFactory{}
    // 传入teddy,产生对应的狗子
	t := factory.MakeDogs("teddy")
	t.Sleep()
	t.Run()
    // 传入chaidog,产生对应的狗子
	c := factory.MakeDogs("chaidog")
	c.Sleep()
	c.Run()
}

简单工厂方法代码

缩小为简单工厂模式。

一个模块仅需要一个工厂类,没有必要把它实例化出来。java使用静态方法就可以了。

场景:

创建狗子的案例:

没有创建狗子的接口工厂

创建狗子的具体工厂(MakeDogs())
狗子接口(sleep()、run())
泰迪、柴犬(具体的狗子)

抽象产品类:

type IDog interface {
	Sleep()
	Run()
}

具体产品类:

柴犬:

// 柴犬
type ChaiDog struct {
}

func (c ChaiDog) Sleep() {
	fmt.Println("睡觉")
}

func (c ChaiDog) Run() {
	fmt.Println("奔跑")
}

泰迪:

// 泰迪
type Teddy struct {
}

func (t Teddy) Sleep() {
	fmt.Println("睡觉")
}

func (t Teddy) Run() {
	fmt.Println("奔跑")
}

抽象工厂类(接口工厂):

去掉。

具体工厂类:

// 工厂方法,这是一个特殊的方法,用来创建不同的狗子
func MakeDogs(dogType string) IDog {
	if dogType == "teddy" {
		return &Teddy{}
	}
	if dogType == "chaidog" {
		return &ChaiDog{}
	}
	return nil
}

场景类:

func main() {
	t := ex.MakeDogs("teddy")
    t.Sleep()
	t.Run()
	c := ex.MakeDogs("chaidog")
	c.Sleep()
	c.Run()
}

工厂方法代码3

升级为多个工厂类。

假如有1个产品类有5个具体实现,每个实现类的初始化方法都不相同,如果写在一个工厂方法中,会导致这个方法巨大无比。

为每一个产品定义一个创建者。

创建狗子的案例:

创建狗子的接口工厂(MakeDogs())

创建泰迪狗子的具体工厂(实现上面的接口)

创建泰迪柴犬的具体工厂(实现上面的接口)

狗子接口(sleep()、run())
泰迪、柴犬(具体的狗子)

接口工厂类:

type IDogFactory interface {
	// 无需再传递参数了
	MakeDogs() IDog
}

抽象产品类:

type IDog interface {
	Sleep()
	Run()
}

具体产品类:

柴犬:

// 柴犬
type ChaiDog struct {
}

func (c ChaiDog) Sleep() {
	fmt.Println("睡觉")
}

func (c ChaiDog) Run() {
	fmt.Println("奔跑")
}

泰迪:

// 泰迪
type Teddy struct {
}

func (t Teddy) Sleep() {
	fmt.Println("睡觉")
}

func (t Teddy) Run() {
	fmt.Println("奔跑")
}

具体工厂:

// 创建柴犬的具体工厂
type ChaiDogFactory struct {
}

func (c ChaiDogFactory) MakeDogs() IDog {
	return &ChaiDog{}
}

// 创建柴犬的具体工厂
type ChaiDogFactory struct {
}

func (c ChaiDogFactory) MakeDogs() IDog {
	return &ChaiDog{}
}

场景类:

func main() {
	f1 := &example.TeddyFactory{}
	dog1 := f1.MakeDogs()
	dog1.Sleep()
	dog1.Run()
	f2 := &example.ChaiDogFactory{}
	dog2 := f2.MakeDogs()
	dog2.Sleep()
	dog2.Run()
}