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

工厂方法模式

什么是工厂方法模式

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

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

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

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

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

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

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

  • 解耦。避免创建者和具体产品之间的紧密耦合。

  • 开闭原则。 无需更改现有客户端代码, 你就可以在程序中引入新的产品类型。;

其缺点是

  • **引入很多新的子类。**应用工厂方法模式需要引入许多新的子类, 代码可能会因此变得更复杂。

角色

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

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

抽象产品类定义产品功能接口。

具体产品类实现Product接口。

抽象工厂类声明工厂方法,定义了创建产品的接口。

具体工厂类实现Creator接口,返回ConcreteProduct。

工厂方法代码

工厂方法模式举例

场景:

创建狗子的案例:

创建狗子,狗子有泰迪、柴犬,以后可能会增加比熊。

注意这里就只有一种类型,就是狗子,没有猫子这个种类。

创建狗子的接口工厂IDogFactory(接口MakeDogs(),返回产品接口)

创建狗子具体工厂DogFactory(实现IDogFactory接口)

狗子接口IDog(sleep()、run(),定义产品功能)

泰迪Teddy、柴犬ChaiDog(具体的狗子)

抽象产品类:

go 复制代码
// idog.go
type IDog interface {
	Sleep()
	Run()
}

具体产品类:

柴犬:

go 复制代码
// caidog.go
// 柴犬
type ChaiDog struct {
}

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

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

泰迪:

go 复制代码
// teddy.go
// 泰迪
type Teddy struct {
}

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

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

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

创建狗子的抽象接口

go 复制代码
// factory.go
type IDogFactory interface {
	MakeDogs(dogType string) IDog
}

具体工厂类:

go 复制代码
// dogfactory.go
type DogFactory struct {
}

// 提供一个方法实例化工厂
func NewDogFactory() Factory {
	return &DogFactory{}
}

// 工厂方法,这是一个特殊的方法,用来创建不同的狗子
func (d *DogFactory) MakeDog(dogType string) IDog {
	switch dogType {
	case "teddy":
		return &Teddy{name: dogType,
			age: 2,
		}
	case "chaidog":
		return &ChaiDog{name: dogType,
			age: 2,
		}
	}
	return nil
}

场景类:

go 复制代码
// client.go
func main() {
	// 创建一个工厂
	f := example.NewFactory()
    // 传入teddy,创建对应的狗子
	teddyDog := f.MakeDog("teddy")
	teddyDog.Sleep()
	teddyDog.Run()
    // 传入chaidog,创建对应的狗子
	cDog := f.MakeDog("chaidog")
	cDog.Sleep()
	cDog.Run()
}

当想加入一个新的产品,例如柯基,添加一个柯基产品子类, 然后重写其工厂方法即可。

简单工厂方法代码

缩小为简单工厂模式。

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

场景:

创建狗子的案例:

创建狗子,狗子有泰迪、柴犬,以后可能会增加比熊。

去掉了工厂接口。

创建狗子的具体工厂DogFactory

狗子接口IDog(sleep()、run(),定义产品功能)

泰迪Teddy、柴犬ChaiDog(具体的狗子)

抽象产品类:

go 复制代码
// idog.go
type IDog interface {
	Sleep()
	Run()
}

具体产品类:

柴犬:

go 复制代码
// caidog.go
// 柴犬
type ChaiDog struct {
}

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

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

泰迪:

go 复制代码
// teddy.go
// 泰迪
type Teddy struct {
}

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

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

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

去掉。

具体工厂类:

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

场景类:

go 复制代码
// client.go
func main() {
	teddyDog := example.MakeDog("teddy")
	teddyDog.Sleep()
	teddyDog.Run()
	cDog := example.MakeDog("chaidog")
	cDog.Sleep()
	cDog.Run()
}

工厂方法代码(升级)

升级为多个具体工厂类。

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

为每一个产品定义一个ConcreteCreator。

创建狗子的案例:

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

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

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

狗子接口(sleep()、run())

泰迪、柴犬(具体的狗子)

接口工厂类:

go 复制代码
// factory.go
type Factory interface {
	// 无需再传递参数了
	MakeDog() IDog
}

抽象产品类:

go 复制代码
// idog.go
type IDog interface {
	Sleep()
	Run()
}

具体产品类:

柴犬:

go 复制代码
// caidog.go
// 柴犬
type ChaiDog struct {
}

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

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

泰迪:

go 复制代码
// teddy.go
// 泰迪
type Teddy struct {
}

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

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

具体工厂:

go 复制代码
// teddyfactory.go
// 创建泰迪的具体工厂
type TeddyFactory struct {
}

func NewTeddyFactory() Factory {
	return &TeddyFactory{}
}

func (d *TeddyFactory) MakeDog() IDog {
	return &Teddy{name: "tom",
		age: 2,
	}
}

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

func NewChaiDogFactory() Factory {
	return &ChaiDogFactory{}
}

func (d *ChaiDogFactory) MakeDog() IDog {
	return &ChaiDog{name: "kate",
		age: 2,
	}
}

场景类:

go 复制代码
// client.go
func main() {
	cf := example.NewChaiDogFactory()
	teddyDog := cf.MakeDog()
	teddyDog.Sleep()
	teddyDog.Run()
	tf := example.NewTeddyFactory()
	caiDog := tf.MakeDog()
	caiDog.Sleep()
	caiDog.Run()
}

如果要扩展一个产品类,需要建立一个相应的工厂类,增加了扩展的难度。

在复杂的应用中一般才用多工厂的方法,然后再增加一个协调类,避免调用者与各个子工厂交流。

相关推荐
da_vinci_x9 小时前
武器设计实战:一把大剑裂变 5 种属性?Structure Ref 的“换肤”魔法
游戏·3d·设计模式·ai作画·aigc·设计师·游戏美术
刀法孜然14 小时前
23种设计模式 3 行为型模式 之3.7 command 命令模式
设计模式·命令模式
一条闲鱼_mytube15 小时前
智能体设计模式(二)反思-工具使用-规划
网络·人工智能·设计模式
老蒋每日coding16 小时前
AI智能体设计模式系列(七)—— 多 Agent 协作模式
设计模式
源代码•宸17 小时前
Golang原理剖析(channel面试与分析)
开发语言·经验分享·后端·面试·golang·select·channel
小码过河.18 小时前
设计模式——代理模式
设计模式·代理模式
moxiaoran575319 小时前
Go语言中的泛型
golang
加油201919 小时前
GO语言内存逃逸和GC机制
golang·内存管理·gc·内存逃逸
源代码•宸19 小时前
Golang原理剖析(channel源码分析)
开发语言·后端·golang·select·channel·hchan·sudog
liuyunshengsir19 小时前
golang Gin 框架下的大数据量 CSV 流式下载
开发语言·golang·gin