设计模式之简单工厂模式

197 阅读3分钟

设计模式之简单工厂模式

工厂模式是最常用的一类创造型设计模式。通常说的工厂模式是指工厂方法模式,他是使用频率最高的工厂模式。这里介绍的简单工厂模式是工厂方法模式的"小弟"

方便面制作

假设现在需要有一个程序去控制方便面的生产,可以根据不同的方便面口味生产出不通的方便面,最简单的设计方法就是如下所示

package simple_factory


type Noodles struct {
	NType string
}

func NewNoodles(NType string)*Noodles{
	noodles := Noodles{
		NType: NType,
	}
	return &noodles
}

func (n *Noodles)Materials()  {
	if n.NType=="红烧牛肉面"{
		// 购买红烧牛肉面原料
	}else if n.NType == "酸菜牛肉面"{
		// 购买酸菜牛肉面原料
	}else if n.NType=="香辣牛肉面" {
		// 购买香辣牛肉面原料
	}
	 
}

func (n *Noodles)Produce()  {
	if n.NType=="红烧牛肉面"{
		// 生产红烧牛肉面
	}else if n.NType == "酸菜牛肉面"{
		// 生产酸菜牛肉面
	}else if n.NType=="香辣牛肉面" {
		// 生产香辣牛肉面
	}
}



但是这样的方法存在很多问题.

  1. 代码中存在大量的if...else... 会影响后期的维护,以及系统的性能
  2. 在增加新的口味的方便面的时候,需要修改Noddles的代码,违反了开闭原则
  3. 对方便面的初始化和生产都在一个结构体下去实现,违反了单一职责原则

等等问题

简单工厂模式概述

首先我们要创建各种不同的结构体(例如不同口味的方便面),这些结构体称之为具体的产品,将他们的公共代码进行抽象和提取放在一个抽象的结构体中,每一个产品结构体都是抽象产品的一个实现,然后提供一个工厂用来创建各个产品,在工厂中提供一个创建产品的方法,该方法可以根据传入不同的参数来创建不同的具体产品实例,客户端只需要调用工厂类的方法传入对应的参数即可得到一个产品实例

定义

简单工厂模式:定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常具有共同的父类,因为在简单工厂模式中用于创建实例的方法是静态方法,因此简单工厂模式又被称之为静态工厂方法模式,它属于创建型模式。

简单工厂模式包括了三个角色

  • Factory(工厂角色)
  • Product(抽象产品角色)
  • ConcreteProduct(具体产品角色)

简单工厂方法改造

这里换了面,因为各种方便面的英文太难搞了

package simple_factory

import "fmt"

type Factory struct {
}

func NewFactory() *Factory {
	return &Factory{}
}

func (f *Factory) GetNoddles(NType string) Noodles {
	if NType == "BeefNoddles" {
		return &BeefNoddles{}
	}
	if NType == "EggNoodles" {
		return &EggNoddles{}
	}
	if NType == "VegNoodles" {
		return &VegNoddles{}
	}
	return nil
}

type Noodles interface {
	Materials() // 购买原材料
	Produce()   // 生产面条
}

// BeefNoddles 牛肉面
type BeefNoddles struct {
}

// EggNoddles 鸡蛋面
type EggNoddles struct {
}

// VegNoddles 蔬菜面
type VegNoddles struct {
}

func (b *BeefNoddles) Materials() {
	fmt.Println("购买牛肉面原料")
}

func (b *BeefNoddles) Produce() {
	fmt.Println("生产牛肉面")
}

func (e *EggNoddles) Materials() {
	fmt.Println("购买鸡蛋面原料")
}

func (e *EggNoddles) Produce() {
	fmt.Println("生产鸡蛋面")
}

func (v *VegNoddles) Materials() {
	fmt.Println("购买蔬菜面原料")
}

func (v *VegNoddles) Produce() {
	fmt.Println("生产蔬菜面")
}

这里的代码对应上面的三个角色分别是

  • Factory ->工厂角色
  • Noodles -> 抽象产品角色
  • 各种面条 -> 具体产品角色

测试方法

func TestNewFactory(t *testing.T) {
	factory := NewFactory()
	beefNoodles := factory.GetNoddles("BeefNoddles")
	beefNoodles.Materials()
	beefNoodles.Produce()

	vegNoddles := factory.GetNoddles("VegNoodles")
	vegNoddles.Materials()
	vegNoddles.Produce()
}

// 输出
// === RUN   TestNewFactory
// 购买牛肉面原料
// 生产牛肉面
// 购买蔬菜面原料
// 生产蔬菜面
// --- PASS: TestNewFactory (0.00s)
// PASS

适用场景

  1. 工厂创建的实例比较少,这样保证了工厂逻辑不会太复杂
  2. 客户端并不关心如何创建对象,只需要知道创建对象的参数