简单工厂模式
简单工厂模式并不属于GoF的23个经典设计模式,但通常将它作为学习其他工厂模式的基础,它的设计思想很简单,其基本流程如下:
首先将需要创建的各种不同对象(例如各种不同的Food对象)的相关代码封装到不同的类中,这些类称为具体产品类,而将它们公共的代码进行抽象和提取后封装在一个抽象产品类中,每一个具体产品类都是抽象产品类的子类;然后提供一个工厂类用于创建各种产品,在工厂类中提供一个创建产品的工厂方法,该方法可以根据所传入的参数不同创建不同的具体产品对象;客户端只需调用工厂类的工厂方法并传入相应的参数即可得到一个产品对象。
需求
快餐店的食物,目前有汉堡,粥,需要向顾客展示价格。
修改前
错误设计
代码
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)
}
}
可以看出有几个问题
- 这个类有很多if…else,代码冗长
- 职责过重,食物相关的所有东西都放在了一起
- 违反开闭原则,添加一款新的食物时就需要修改这个类
修改后
正确设计
代码实现
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
总结
适用场景
- 工厂类负责创建的对象比较少,不会造成工厂方法中的业务逻辑太过复杂。
- 客户端只知道传入工厂类的参数,并不关心如何创建对象。
优点
- 简单工厂模式实现了对象创建和使用的分离。工厂类包含必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以仅仅使用产品。
- 简单工厂模式可以在一定程度减少使用者的记忆量。客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可。
缺点
- 由于工厂类集中了所有产品的创建逻辑,职责过重,一旦不能正常工作,整个系统都要受到影响。
- 使用简单工厂模式势必会增加系统中类的个数,增加了系统的复杂度和理解难度。
- 系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。