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()
}

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

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

相关推荐
JWASX3 小时前
Java 转 go 学习 - 基本语法
学习·golang
Zane19944 小时前
工厂方法一定比简单工厂高级?三种工厂模式到底该怎么选
设计模式
Hespethorn5 小时前
设计模式是语言缺陷的补丁 —— 从工厂、单例、策略三个模式说起
设计模式
Lost of 程序猿5 小时前
命令模式实战:把“下单后的动作“打包成可执行的任务
后端·设计模式·c#·asp.net·命令模式
一只旭宝5 小时前
【C++复习】四种类型转换 + 常见设计模式 + Redis/MySQL(后端面试复习完整版)
c++·redis·笔记·mysql·设计模式
microrain6 小时前
首包即身份:SagooIoT 网络组件的注册包、粘包与透传设计
物联网·golang·开源·sagooiot
GoFly开发者7 小时前
纯 Go 桌面 AI 智能体实战:Wails3 + Eino ADK 构建 Agent 对话应用(流式输出 / 工具审批 / RAG / 打包全记录)
golang·ai agent·eino·wails3·agent桌面开发
YYYing.7 小时前
【设计模式系列 (四) 】建造者模式
c++·后端·设计模式·建造者模式·c/c++
小小龙学IT19 小时前
三菱 PLC MC 协议(SLMP / QnA 兼容 3E 帧)深度解析:从帧结构到 C++/Go 双语言采集实战
c语言·c++·golang
念何架构之路20 小时前
zap日志SugaredLogger 剖析
云原生·golang