Go 语言实现创建型设计模式 - 工厂模式

开发 前端
在介绍工厂模式的使用场景之前,我们需要先简单了解工厂模式的组成结构,一般分为抽象产品、具体产品、抽象工厂和具体工厂。

​01 介绍

工厂模式是一种创建型设计模式,包含三种类型,分别是简单工厂、工厂方法和抽象工厂。

在《设计模式》[1]一书中,因为 GoF[2] 认为简单工厂是工厂方法的一种特例,所以 GoF 把工厂模式分为两种类型,分别是工厂方法和抽象工厂。

本文我们使用第一种分类方式,分别介绍一下工厂模式的三种类型。

02 使用场景

在介绍工厂模式的使用场景之前,我们需要先简单了解工厂模式的组成结构,一般分为抽象产品、具体产品、抽象工厂和具体工厂。

注意:简单工厂模式,不区分抽象工厂和具体工厂。

简单工厂

简单工厂适用于具体产品较少,且不会频繁添加具体产品的场景。因为每多一个具体产品,在工厂中就多一个 if 分支。

工厂方法

工厂方法适用于具体产品较多,且需要频繁添加具体产品的场景。使用工厂方法可以避免使用 if 分支,当我们需要添加具体产品时,只需创建新的具体产品和具体工厂,符合开闭原则和单一职责原则。

而且还可以将每个具体产品的创建逻辑拆分到不同的工厂中,避免使用一个工厂导致的代码过于复杂。

注意:拆分多个工厂,则需要维护多个工厂的代码。

抽象工厂

抽象工厂适用于一个具体工厂需要负责生产多个不同产品,并且工厂的职责不会继续增加的场景(即抽象工厂定义的一组方法不会继续增加)。

否则,不仅所有具体工厂都需要修改,抽象产品和具体产品也需要修改,违反开闭原则。

03 实现方式

简单工厂

简单工厂模式违反了开闭原则,严格意义上不算是一个设计模式,它主要包括三个结构,分别是工厂、抽象产品和具体产品。

  • 工厂 - 负责调用具体产品生产产品,返回值是抽象产品(接口)。
  • 抽象产品 - 负责定义产品,接口类型,包含一组方法。
  • 具体产品 - 负责被工厂调用,实现抽象产品(接口)。

工厂方法

工厂方法模式符合开闭原则,它相比简单工厂模式,多了一个抽象工厂的结构,总共包括四个结构,分别是抽象工厂、具体工厂、抽象产品和具体产品。

  • 抽象工厂(单个) - 负责定义工厂,接口类型,包含一组方法。
  • 具体工厂(多个) - 负责通过实例化具体产品创建产品,实现抽象工厂(接口)。
  • 抽象产品(单个) - 负责定义产品,接口类型,包含一组方法。
  • 具体产品(多个) - 负责被具体工厂调用,实现抽象产品(接口)。

注意:此处“抽象工厂”是工厂方法模式中的一个结构,不要与抽象工厂模式混淆。

抽象工厂

抽象工厂模式也是总共包括四个结构,它与工厂方法模式不同,工厂方法模式中抽象产品只有一个,而抽象工厂模式抽象产品有多个。

但是,四个结构的职责与工厂方法模式相同。

  • 抽象工厂(单个)
  • 具体工厂(多个)
  • 抽象产品(多个)
  • 具体产品(多个)

04 Go 实现

简单工厂

// IDrink 抽象产品 - 饮料
type IDrink interface {
Kind() // 抽象方法 - 类别
Name() // 抽象方法 - 名称
}

// CocaCola 具体产品 - 可口可乐
type CocaCola struct {
}

// Kind 具体方法
func (c *CocaCola) Kind() {
fmt.Println("carbonated drinks")
}

// Name 具体方法
func (c *CocaCola) Name() {
fmt.Println("CocaCola")
}

// Sprite 具体产品 - 雪碧
type Sprite struct {
}

// Kind 具体方法
func (s *Sprite) Kind() {
fmt.Println("carbonated drinks")
}

// Name 具体方法
func (s *Sprite) Name() {
fmt.Println("Sprite")
}

// SimpleFactory 工厂
type SimpleFactory struct {
}

// Produce 生产 - 返回值(抽象产品)
func (s *SimpleFactory) Produce(name string) (drink IDrink) {
if name == "CocaCola" {
drink = new(CocaCola)
} else if name == "Sprite" {
drink = new(Sprite)
}
return
}

阅读上面这段代码,我们可以发现,我们通过代码定义简单工厂模式的三个结构。

定义一个包含一组方法的 IDrink 接口,代表抽象产品;

定义一个 CocaCola​ 结构体和一个 Sprite​ 结构体,并都实现 IDrink 接口,代表具体产品;

定义一个 SimpleFactory​ 结构体,并定义一个返回值是 IDrink​ 的 Produce 方法,代表工厂。

工厂方法

// IDrink 抽象产品
type IDrink interface {
Kind() // 抽象方法
Name() // 抽象方法
}

// CocaCola 具体产品
type CocaCola struct {
}

// Kind 具体方法
func (c *CocaCola) Kind() {
fmt.Println("carbonated drinks")
}

// Name 具体方法
func (c *CocaCola) Name() {
fmt.Println("CocaCola")
}

// Sprite 具体产品
type Sprite struct {
}

// Kind 具体方法
func (s *Sprite) Kind() {
fmt.Println("carbonated drinks")
}

// Name 具体方法
func (s *Sprite) Name() {
fmt.Println("Sprite")
}

// IFactory 抽象工厂
type IFactory interface {
Produce() IDrink // 抽象方法
}

// CocaColaFactory 具体工厂
type CocaColaFactory struct {
}

// Produce 具体方法
func (c *CocaColaFactory) Produce() (drink IDrink) {
drink = new(CocaCola)
return
}

// SpriteFactory 具体工厂
type SpriteFactory struct {
}

// Produce 具体方法
func (s *SpriteFactory) Produce() (drink IDrink) {
drink = new(Sprite)
return
}

阅读上面这段代码,我们通过代码定义工厂方法模式的四个结构。

定义一个包含一组方法的 IDrink 接口,代表抽象产品;

定义一个 CocaCola​ 结构体和一个 Sprite​ 结构体,并都实现 IDrink 接口,代表具体产品;

定义一个包含一组方法的 IFactory 接口,代表抽象工厂;

定义一个 CocaColaFactory​ 结构体和一个 SpriteFactory​ 结构体,并都实现 IFactory 接口,代表具体工厂;

抽象工厂

// AbstractCola 抽象 Cola
type AbstractCola interface {
ColaKind() // 抽象方法
ColaName() // 抽象方法
}

// AbstractSprite 抽象 Sprite
type AbstractSprite interface {
SpriteKind() // 抽象方法
SpriteName() // 抽象方法
}

// AbstractFactory 抽象工厂
type AbstractFactory interface {
ProduceCola() AbstractCola // 抽象方法
ProduceSprite() AbstractSprite // 抽象方法
}

// CocaBrandCola 可口品牌 具体 Cola 产品
type CocaBrandCola struct {
}

func (c *CocaBrandCola) ColaKind() {
fmt.Println("Coca Brand carbonated drinks")
}

func (c *CocaBrandCola) ColaName() {
fmt.Println("Coca Brand Cola")
}

// CocaBrandSprite 可口品牌 具体 Sprite 产品
type CocaBrandSprite struct {
}

func (c *CocaBrandSprite) SpriteKind() {
fmt.Println("Coca Brand carbonated drinks")
}

func (c *CocaBrandSprite) SpriteName() {
fmt.Println("Coca Brand Sprite")
}

// CocaFactory 可口品牌 具体工厂
type CocaFactory struct {
}

func (c *CocaFactory) ProduceCola() (cola AbstractCola) {
cola = new(CocaBrandCola)
return
}

func (c *CocaFactory) ProduceSprite() (sprite AbstractSprite) {
sprite = new(CocaBrandSprite)
return
}

// PepsiBrandCola 百事品牌 具体 Cola 产品
type PepsiBrandCola struct {
}

func (p *PepsiBrandCola) ColaKind() {
fmt.Println("Pepsi Brand carbonated drinks")
}

func (p *PepsiBrandCola) ColaName() {
fmt.Println("Pepsi Brand Cola")
}

// PepsiBrandSprite 百事品牌 具体 Sprite 产品
type PepsiBrandSprite struct {
}

func (p *PepsiBrandSprite) SpriteKind() {
fmt.Println("Pepsi Brand carbonated drinks")
}

func (p *PepsiBrandSprite) SpriteName() {
fmt.Println("Pepsi Brand Sprite")
}

// PepsiFactory 百事品牌 具体工厂
type PepsiFactory struct {
}

func (p *PepsiFactory) ProduceCola() (cola AbstractCola) {
cola = new(PepsiBrandCola)
return
}

func (p *PepsiFactory) ProduceSprite() (sprite AbstractSprite) {
sprite = new(PepsiBrandSprite)
return
}

阅读上面这段代码,我们通过代码定义抽象工厂模式的四个结构。

定义一个包含一组方法的 AbstractCola​ 接口,和一个包含一组方法的 AbstractSprite 接口,均代表抽象产品(多个抽象产品);

定义一个 CocaBrandCola​ 结构体,实现 AbstractCola​ 接口;定义一个 CocaBrandSprite​ 结构体,实现 AbstractSprite 接口;均代表具体产品(多个具体产品);

定义一个包含一组方法的 AbstractFactory 接口,代表抽象工厂;

定义一个 CocaFactory​ 结构体,实现 AbstractFactory​ 接口;定义一个 PepsiFactory​ 结构体,实现 AbstractFactory 接口;均代表具体工厂(多个具体工厂);

05 总结

本文介绍的三种工厂模式中,简单工厂和工厂方法比较常用,抽象工厂使用较少。

其中,简单工厂适用于具体产品较少,且不会频繁添加具体产品的场景;

工厂方法适用于具体产品较多,且需要频繁添加具体产品的场景;

还有就是生产具体产品,代码比较复杂,不只是实例化具体产品,还需要其他业务逻辑的场景;

或不希望代码中使用一堆 if 分支的场景。

参考资料

​[1]《设计模式》: https://en.wikipedia.org/wiki/Design_Patterns

[2]GoF: http://wiki.c2.com/?GangOfFour

责任编辑:武晓燕 来源: Golang语言开发栈
相关推荐

2023-11-02 21:11:11

JavaScript设计模式

2021-03-06 22:50:58

设计模式抽象

2020-08-21 07:23:50

工厂模式设计

2022-01-12 13:33:25

工厂模式设计

2011-11-17 16:03:05

Java工厂模式Clojure

2023-03-21 07:57:37

Go语言设计模式

2021-09-29 13:53:17

抽象工厂模式

2020-10-19 09:28:00

抽象工厂模式

2023-05-04 08:47:31

命令模式抽象接口

2023-04-10 09:20:13

设计模式访客模式

2024-03-06 13:19:19

工厂模式Python函数

2010-04-19 09:30:00

工厂模式PHP设计模式

2023-05-15 08:51:46

解释器模式定义

2009-01-15 10:55:29

JavaScript设计模式抽象工厂

2013-11-26 16:29:22

Android设计模式

2010-10-09 09:25:35

Python工厂模式

2022-05-09 08:04:50

工厂模式设计模式

2011-07-28 09:50:58

设计模式

2015-11-03 09:43:43

avascript设计模式工厂模式

2019-08-16 10:46:46

JavaScript工厂模式抽象工厂模式
点赞
收藏

51CTO技术栈公众号