介绍
工厂模式是一种创建型设计模式,包含三种类型,分别是简单工厂、工厂方法和抽象工厂。
在《设计模式》[1]一书中,因为 GoF[2] 认为简单工厂是工厂方法的一种特例,所以 GoF 把工厂模式分为两种类型,分别是工厂方法和抽象工厂。
本文我们使用第一种分类方式,分别介绍一下工厂模式的三种类型。
使用场景
在介绍工厂模式的使用场景之前,我们需要先简单了解工厂模式的组成结构,一般分为抽象产品、具体产品、抽象工厂和具体工厂。
注意:简单工厂模式,不区分抽象工厂和具体工厂。
简单工厂
简单工厂适用于具体产品较少,且不会频繁添加具体产品的场景。因为每多一个具体产品,在工厂中就多一个 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
分支的场景。