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

本文介绍了简单工厂模式的基本概念和应用场景,通过一个错误的设计示例展示了如何将一个充斥着if...else的冗余代码重构为遵循开闭原则的正确设计。在错误设计中,工厂类职责过重,而重构后的设计实现了接口,每个产品类独立,新增产品只需添加新类。测试结果显示重构后的设计更加灵活且易于扩展。
摘要由CSDN通过智能技术生成


简单工厂模式

简单工厂模式并不属于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)
	}
}

可以看出有几个问题

  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

总结

适用场景

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

优点

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

缺点

  • 由于工厂类集中了所有产品的创建逻辑,职责过重,一旦不能正常工作,整个系统都要受到影响。
  • 使用简单工厂模式势必会增加系统中类的个数,增加了系统的复杂度和理解难度。
  • 系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lady_killer9

感谢您的打赏,我会加倍努力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值