简单工厂模式
·
工厂模式
工厂模式分类:
简单工厂模式、工厂方法模式、抽象工厂模式、容器工厂模式
使用背景:
在Go语言中没有针对类的构造器方法定义统一的规范,倘若每次需要创建类的实例时,都需要在业务方法中事无俱细地执行实例初始化的细节,那么会存在缺陷的包括:
- 业务方法和组件类之间产生过高的耦合度,需要了解组件类的过多细节
- 如果组件类的定义发生更改,那么散落在各处的业务方法中对类的构造流程都需要配合改动
如何解决上述问题?只需要只能一个中间层解决就可以了!

工厂类可以带来的好处:
- 实现类和业务方法之间的解耦,如果类的构造过程发生变更,可以统一收口在工厂类中进行处理,从而对业务方法屏蔽相关细节
- 倘若有多个类都聚拢在工厂类中进行构造,这样各个类的构造流程中就天然形成了一个公共的切面,可以进行一些公共逻辑的执行
简单工厂模式:
简单定义:
可以根据不同参数返回不同的类的实例,被创建的类通常有共同的父类
假设我们有这样场景:
- 有个抽象的Fruit interface !赋予Fruit一个Eat的方法
- 有三个Fruit的具体实现类,Orange、Strawberry和cherry,都是实现了Eat方法
- 有一个具体Factory 可以使用方法CreateFruit 根据用户的指定类型创建不同Fruit的实例!
UML类图如下:

具体实现如下:
// Fruit接口
type Fruit interface{
Eat()
}
type Orange struct{
name string
}
func (o *Orange)Eat(){
fmt.Println("Orange implement Fruit Eat() method...")
}
func NewOrange(name string) Fruit{
return &Orange{
name:name,
}
}
type Strawberry struct{
name string
}
func (s *Strawberry)Eat(){
fmt.Println("Strawberry implement Fruit Eat() method...")
}
func NewStrawberry(name string) Fruit{
return &Strawberry{
name:name,
}
}
type Cherry struct{
name string
}
func (c *Cherry)Eat(){
fmt.Println("Cherry implement Fruit Eat() method...")
}
func NewCherry(name string) Fruit{
return &Cherry{
name:name,
}
}
下面是关于生产水果的工厂类 FruitFactory 的定义,其中 CreateFruit 方法是用于生产水果的核心方法:
- 利用工厂生产三类时存在的公共切面,进行随机数的取值,用来给生产出来的水果命名
- 根据使用方传入的水果类型 typeNmae ,调用对应水果类型的构造器方法,并将生产出来的水果进行返回
- 如果使用方法传入的水果类型 typeNmae 非法,则对外抛出错误
// FruitFactory 定义工厂类
type FruitFactory struct{
}
// NewFruitFactory 获取工厂实例
func NewFruitFactory() *FruitFactory{
return &FruitFactory{}
}
// CreateFruit 根据类型返回不同的实例对象
func (f *FruitFactory)CreateFruit(typeName string) (Fruit,error){
src:=rand.NewSource(time.Now().UnixNano())
//New返回一个新的Rand,它使用来自src的随机值来生成其他随机值。
rander:=rand.New(src)
name:=strconv.Itoa(rander.Int())
switch typeName{
case "orange":
return NewOrange(name),nil
case "strawberry":
return NewStrawberry(name),nil
case "cherry":
return NewCherry(name),nil
default:
return nil,fmt.Errorf("fruit typeName: %s is not supported yet", typeName)
}
}
测试:
func Test_factory(t *testing.T) {
// 构造工厂
fruitFactory := NewFruitFactory()
// 尝个橘子
orange, _ := fruitFactory.CreateFruit("orange")
orange.Eat()
// 来颗樱桃
cherry, _ := fruitFactory.CreateFruit("cherry")
cherry.Eat()
// 来个西瓜,因为未实现会报错
watermelon, err := fruitFactory.CreateFruit("watermelon")
if err != nil {
t.Error(err)
return
}
watermelon.Eat()
}
工厂模式的优缺点:
- 优点:实现对象的创建和分离,对于客户端的程序员来说不需要关心怎么创建的,只关心怎么使用就可以了
- 缺点:不够灵活,不利于类的拓展
工厂方法模式
为了解决简单工厂模式中存在的问题,对设计流程进行修改:
- 关于组件的定义模式不变. 一个抽象的 Fruit interface,多个具体的水果实现 Orange、Strawberry、Cherry
- 将工厂类 FruitFactory 由具体的实现类改为抽象的 interface
- 针对每类水果,提供出一个具体的工厂实现类,如 OrangeFactory、StrawberryFactory、CherryFactory
UML类图如下:

在工厂方法模式中,Fruit interface 以及几个具体实现类 Orange、Strawberry 和 Cherry 的定义和简单工厂模式如出一辙!
与简单工厂模式的区别是,水果工厂类 FruitFactory 在此处变成一个抽象的 interface,且针对每种具体的水果实现类需要对应地声明一种工厂实现类,包括 OrangeFactory、StrawberryFactory、CherryFactory,具体的实现代码如下:
type FruitFactory interface {
CreateFruit() Fruit
}
type OrangeFactory struct {
}
func (o *OrangeFactory) CreateFruit() Fruit {
return NewOrange("")
}
type StrawberryFactory struct {
}
func (s *StrawberryFactory) CreateFruit() Fruit {
return NewStrawberry("")
}
type CherryFactory struct {
}
func (c *CherryFactory) CreateFruit() Fruit {
return NewCherry("")
}
func NewOrangeFactory() FruitFactory {
return &OrangeFactory{}
}
func NewStrawberryFactory() FruitFactory {
return &StrawberryFactory{}
}
func NewCherryFactory() FruitFactory {
return &CherryFactory{}
}
这样的设计模式下,即便后续有频繁扩展水果实现类的需求,也无须对老模块的代码进行修改,而是需要扩展实现一个水果 Fruit 的实现类以及对应的水果工厂实现类即可,比如,倘若此处我们需要在水果列表中扩展一个“西瓜”的话,那么需要新增的代码如下:
type Watermelon struct {
name string
}
func NewWatermelon(name string) Fruit {
return &Watermelon{
name: name,
}
}
func (w *Watermelon) Eat() {
fmt.Printf("i am watermelon: %s, i am about to be eaten...", w.na
type WatermelonFactory struct {
}
func NewWatermelon() FruitFactory {
return &WatermelonFactory{}
}
func (w *WatermelonFactory) CreateFruit() Fruit {
return NewWatermelon("")
}
工厂方法模式相较于简单工厂模式而言,解决了扩展水果类不满足开闭原则的问题,然而工厂方法模式也有其固有的缺陷:
- 需要为每个水果单独实现一个工厂类,代码冗余度较高
- 原本构造多个水果类时存在的公共切面不复存在,一些通用的逻辑需要在每个水果工厂实现类中重复声明一遍
更多推荐
所有评论(0)