设计模式-简单工厂模式(Go实现)

 

目录

  • 简单工厂模式
  • 需求
  • 修改前
    • 错误设计
    • 代码
  • 修改后
    • 正确设计
    • 代码实现
  • 测试
    • 测试代码
    • 测试结果
  • 总结
    • 适用场景
    • 优势
    • 缺点

 


简单工厂模式

简单工厂模式并不属于GoF的23个经典设计模式,但一般将它做为学习其余工厂模式的基础,它的设计思想很简单,其基本流程以下:设计模式

首先将须要建立的各类不一样对象(例如各类不一样的Food对象)的相关代码封装到不一样的类中,这些类称为具体产品类,而将它们公共的代码进行抽象和提取后封装在一个抽象产品类中,每个具体产品类都是抽象产品类的子类;而后提供一个工厂类用于建立各类产品,在工厂类中提供一个建立产品的工厂方法,该方法能够根据所传入的参数不一样建立不一样的具体产品对象;客户端只需调用工厂类的工厂方法并传入相应的参数便可获得一个产品对象。ide

需求

快餐店的食物,目前有汉堡,粥,须要向顾客展现价格。学习

修改前

错误设计

在这里插入图片描述

代码

package SimpleFactory

import "fmt"

type Food struct {
	price int
	type_ string
}

func NewFood(t string) *Food {
	if t == "hamburger"{
		return &Food{
			type_: t,
			price: 13,
		}
	}else if t == "porridge"{
		return &Food{
			type_: t,
			price: 8,
		}
	}
	return nil
}

func (f Food)Display()  {
	if f.type_ == "hamburger"{
		fmt.Println("I'm Hamburger, price is ",f.price)
	}else if f.type_ == "porridge"{
		fmt.Println("I'm Porridge, price is ",f.price)
	}
}

能够看出有几个问题测试

  1. 这个类有不少if…else,代码冗长
  2. 职责太重,食物相关的全部东西都放在了一块儿
  3. 违反开闭原则,添加一款新的食物时就须要修改这个类
修改后

正确设计

在这里插入图片描述

代码实现

package SimpleFactory

import (
	"fmt"
)

type Foods interface {
	Display()
}

type Hamburger struct {
	price int
}

func (h Hamburger) Display() {
	fmt.Println("I'm Hamburger, price is ",h.price)
}

type Porridge struct {
	price int
}

func (p Porridge) Display() {
	fmt.Println("I'm Porridge, price is ",p.price)
}

type FoodsFactory struct {

}

func (f FoodsFactory)GetFood(name string) Foods {
	switch name {
	case "hamburger":
		return & Hamburger{price: 10}
	case "porridge":
		return &Porridge{price: 8}
	default:
		return nil
	}
}

相对于修改前,增长一个食品时只须要新增一个类,实现Display方法便可,不对原来的汉堡和粥的代码修改,维护工厂类的GetFood方法便可。
简化:去除工厂类,将工厂方法(GetFood)与抽象类/接口(Foods)合并设计

测试

测试代码

package SimpleFactory

import (
	"fmt"
	"testing"
)

func TestWrong(t *testing.T) {
	ham := NewFood("hamburger")
	ham.Display()
	por := NewFood("porridge")
	por.Display()
	wrong := NewFood("not exist")
	fmt.Println(wrong)
}

func TestSimple(t *testing.T) {
	f := FoodsFactory{}
	ham := f.GetFood("hamburger")
	ham.Display()
	por := f.GetFood("porridge")
	por.Display()
	wrong := f.GetFood("not exist")
	fmt.Println(wrong)
}

测试结果

=== RUN TestSimple
I’m Hamburger, price is 10
I’m Porridge, price is 8

— PASS: TestSimple (0.00s)
PASS对象

总结

适用场景

  • 工厂类负责建立的对象比较少,不会形成工厂方法中的业务逻辑太过复杂。
  • 客户端只知道传入工厂类的参数,并不关心如何建立对象。

优势

  • 简单工厂模式实现了对象建立和使用的分离。工厂类包含必要的判断逻辑,能够决定在何时建立哪个产品类的实例,客户端能够仅仅使用产品。
  • 简单工厂模式能够在必定程度减小使用者的记忆量。客户端无须知道所建立的具体产品类的类名,只须要知道具体产品类所对应的参数便可。

缺点

  • 因为工厂类集中了全部产品的建立逻辑,职责太重,一旦不能正常工做,整个系统都要受到影响。
  • 使用简单工厂模式势必会增长系统中类的个数,增长了系统的复杂度和理解难度。
  • 系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时,有可能形成工厂逻辑过于复杂,不利于系统的扩展和维护。