go语言实现简单工厂模式

本文介绍了如何使用Go语言实现简单工厂模式,通过对比不同版本的代码展示其优势和缺点。简单工厂模式能实现对象创建与使用的解耦,但增加新产品时需要修改工厂类,违反开闭原则。文中还探讨了适用的场景,如对象创建过程复杂或子类有共同属性和方法的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

本系列文章将介绍使用go语言实现23种设计模式,今天将要介绍的是使用go语言实现简单工厂模式。

定义

简单工厂的定义:提供创建对象的接口。

关键:

1.公共父类:定义公共属性,公共的方法,所有子类都必须有这些公共属性和公共方法。它是工厂类创建的所有对象的父类,封装了各种产品对象的共有方法

2.继承公共父类的子类:在继承父类基础上,增加区别与其他子类的业务。它是简单工厂模式的创建目标。

3.生产子类的工厂:用于new各个子类的中间类。也即是:Factory(工厂角色):即工厂类,它是简单工厂模式的核心,负责实现创建所有产品实例的内部逻辑;其可以被外界直接调用,创建所需的产品对象。

例子

实现一个发不同样式短信的功能,比如说可以发纯文本的短信,带视频的短信,带卡片的短信,纯图片的短信等。

版本1.0的代码如下所示:

package main

import (
   "errors"
   "fmt"
   "github.com/prometheus/common/log"
)

/**
实现发不同样式的短信版本1.0
*/

const (
   _ = iota
   Text
   Picture
   Card
   Video
)

func SendText(content string, typ int) (isSuccess bool, err error) {
   if typ != Text {
      err = errors.New("140001")
      return
   }
   if content == "" {
      err = errors.New("150001")
      log.Errorf("发送内容不能空 content(%+v) err(%+v)", content, err)
      return
   }
   isSuccess = true
   fmt.Printf("发送的内容为:%s\n", content)
   return
}

func SendPicture(content string, typ int) (isSuccess bool, err error) {
   if typ != Picture {
      err = errors.New("1400002")
      return
   }
   if content == "" {
      err = errors.New("150002")
      log.Errorf("发送内容不能空 content(%+v) err(%+v)", content, err)
      return
   }
   // 获取图片的内容,校验图片等
   isSuccess = true
   fmt.Printf("发送的内容为:%s\n", content)
   return
}

func SendCard(content string, typ int) (isSuccess bool, err error) {
   if typ != Card {
      err = errors.New("140003")
      return
   }
   if content == "" {
      err = errors.New("150003")
      log.Errorf("发送内容不能空 content(%+v) err(%+v)", content, err)
      return
   }
   // 获取卡片的参数校验
   isSuccess = true
   fmt.Printf("发送的内容为:%s\n", content)
   return
}

func SendVideo(content string, typ int) (isSuccess bool, err error) {
   if typ != Video {
      err = errors.New("140004")
      return
   }
   if content == "" {
      err = errors.New("150004")
      log.Errorf("发送内容不能空 content(%+v) err(%+v)", content, err)
      return
   }
   // 获取视频的参数校验
   isSuccess = true
   fmt.Printf("发送的内容为:%s\n", content)
   return
}

func main() {
   var (
      typ       = 1
      content   = "我是文本私信"
      isSuccess bool
      err       error
   )
   switch typ {
   case Text:
      isSuccess, err = SendText(content, Text)
      if err != nil {
         log.Fatal(err)
         return
      }
   case Picture:
      isSuccess, err = SendPicture(content, Picture)
      if err != nil {
         log.Fatal(err)
         return
      }
   case Card:
      isSuccess, err = SendCard(content, Card)
      if err != nil {
         log.Fatal(err)
         return
      }
   case Video:
      isSuccess, err = SendVideo(content, Video)
      if err != nil {
         log.Fatal(err)
         return
      }
   }
   if isSuccess {
      fmt.Println("消息发送成功")
      return
   }
   fmt.Println("消息发送失败")
}

这段代码的缺点:

1.完全没有使用面向对象的编程

2.不容易维护,扩展性不强,不符合开闭原则,每次增加新的功能都需要修改这段代码

3.各个功能耦合度太高

4.不灵活

5.。。。。

版本2.0的代码

package main

import (
	"errors"
	"fmt"
	"github.com/prometheus/common/log"
)

/**
发短信2.0
使用面向对象的思想
*/

const (
	_ = iota
	TextType
	PictureType
	CardType
	VideoType
)

type Message struct {
	Content  string
	Sender   string // 发送人
	Receiver string // 接收者
	Params   string //接收参数
}

type SendResult struct {
	isSuccess bool
}

func (msg *Message) CheckParams() (err error) {
	if msg.Content == "" {
		err = errors.New("601")
		log.Errorf("发送内容不能为空 err(%+v)", err)
		return
	}
	if msg.Sender == "" {
		err = errors.New("602")
		log.Errorf("发送人不能为空 err(%+v)", err)
		return
	}
	if len(msg.Receiver) == 0 {
		err = errors.New("603")
		log.Errorf("接收人不能为空")
	}
	return
}

func Send(sender, receiver, content string) (res bool, err error) {
	if content == "" {
		err = errors.New("14000")
		log.Errorf("发送内容不能为空 content(%s) err(%+v)", content, err)
		return
	}
	fmt.Printf("%s发送消息给:%s\n", sender, receiver)
	fmt.Println(content)
	res = true
	return
}

type SendMsg interface {
	SendMsg(msg *Message) (sendResult *SendResult, err error)
}

type TextMsg struct {
	Typ     int
	Message *Message
}

func (text *TextMsg) SendMsg(msg *Message) (res *SendResult, err error) {
	res = new(SendResult)
	if text.Typ != TextType {
		err = errors.New("151")
		log.Errorf("消息类型不合法 err(%+v)", err)
		return
	}
	err = text.Message.CheckParams()
	if err != nil {
		log.Errorf("参数校验不合法 err(%+v)", err)
		return
	}
	res.isSuccess, err = Send(msg.Sender, msg.Receiver, "文本消息:"+msg.Content)
	if err != nil {
		log.Errorf("sendMsg err(%+v)", err)
		return
	}
	return
}

type PictureMsg struct {
	Typ     int
	Message *Message
}

func (text *PictureMsg) SendMsg(msg *Message) (res *SendResult, err error) {
	res = new(SendResult)
	if text.Typ != PictureType {
		err = errors.New("152")
		log.Errorf("消息类型不合法 err(%+v)", err)
		return
	}
	err = text.Message.CheckParams()
	if err != nil {
		log.Errorf("参数校验不合法 err(%+v)", err)
		return
	}
	res.isSuccess, err = Send(msg.Sender, msg.Receiver, "图片消息:"+msg.Content)
	if err != nil {
		log.Errorf("sendMsg err(%+v)", err)
		return
	}
	return
}

type CardMsg struct {
	typ     int
	Message *Message
}

func (text *CardMsg) SendMsg(msg *Message) (res *SendResult, err error) {
	res = new(SendResult)
	if text.typ != CardType {
		err = errors.New("153")
		log.Errorf("消息类型不合法 err(%+v)", err)
		return
	}
	err = text.Message.CheckParams()
	if err != nil {
		log.Errorf("参数校验不合法 err(%+v)", err)
		return
	}
	res.isSuccess, err = Send(msg.Sender, msg.Receiver, "卡片消息:"+msg.Content)
	if err != nil {
		log.Errorf("CardMsg err(%+v)", err)
		return
	}
	return
}

type VideoMsg struct {
	typ     int
	Message *Message
}

func (text *VideoMsg) SendMsg(msg *Message) (res *SendResult, err error) {
	res = new(SendResult)
	if text.typ != VideoType {
		err = errors.New("154")
		log.Errorf("消息类型不合法 err(%+v)", err)
		return
	}
	err = text.Message.CheckParams()
	if err != nil {
		log.Errorf("参数校验不合法 err(%+v)", err)
		return
	}
	res.isSuccess, err = Send(msg.Sender, msg.Receiver, "视频消息:"+msg.Content)
	if err != nil {
		log.Errorf("sendMsg err(%+v)", err)
		return
	}
	return
}

func main() {
	// 客户端代码
	message := &Message{
		Content:  "在吗",
		Sender:   "张三",
		Receiver: "李四",
	}
	text := PictureMsg{
		Typ:     2,
		Message: message,
	}
	res, err := text.SendMsg(message)
	if err != nil {
		log.Errorf("err(%+v)", err)
	}

	if res.isSuccess {
		fmt.Println("消息发送成功")
	} else {
		fmt.Println("消息发送失败")
	}
}

缺点:

1.耦合性太高,而且如果要增加一个短信的类型,要修改代码

2.每次都要new一个对象,客户端要每次判断前端传过来的对象,使用switch

版本3.0代码之-简单工厂

package main

import (
	"errors"
	"fmt"
	"github.com/prometheus/common/log"
)

/**
发短信2.0
使用面向对象的思想
*/

const (
	_ = iota
	TextType
	PictureType
	CardType
	VideoType
)

type Message struct {
	Content  string
	Sender   string // 发送人
	Receiver string // 接收者
	Params   string //接收参数
}

type SendResult struct {
	isSuccess bool
}

func (msg *Message) CheckParams() (err error) {
	if msg.Content == "" {
		err = errors.New("601")
		log.Errorf("发送内容不能为空 err(%+v)", err)
		return
	}
	if msg.Sender == "" {
		err = errors.New("602")
		log.Errorf("发送人不能为空 err(%+v)", err)
		return
	}
	if len(msg.Receiver) == 0 {
		err = errors.New("603")
		log.Errorf("接收人不能为空")
	}
	return
}

func Send(sender, receiver, content string) (res bool, err error) {
	if content == "" {
		err = errors.New("14000")
		log.Errorf("发送内容不能为空 content(%s) err(%+v)", content, err)
		return
	}
	fmt.Printf("%s发送消息给:%s\n", sender, receiver)
	fmt.Println(content)
	res = true
	return
}

type SendMsg interface {
	SendMsg() (sendResult *SendResult, err error)
}

type TextMsg struct {
	*Message
}

func (text *TextMsg) SendMsg() (res *SendResult, err error) {
	res = new(SendResult)
	err = text.Message.CheckParams()
	if err != nil {
		log.Errorf("参数校验不合法 err(%+v)", err)
		return
	}
	res.isSuccess, err = Send(text.Sender, text.Receiver, "文本消息:"+text.Content)
	if err != nil {
		log.Errorf("sendMsg err(%+v)", err)
		return
	}
	return
}

type PictureMsg struct {
	*Message
}

func (text *PictureMsg) SendMsg() (res *SendResult, err error) {
	res = new(SendResult)
	err = text.Message.CheckParams()
	if err != nil {
		log.Errorf("参数校验不合法 err(%+v)", err)
		return
	}
	res.isSuccess, err = Send(text.Sender, text.Receiver, "图片消息:"+text.Content)
	if err != nil {
		log.Errorf("sendMsg err(%+v)", err)
		return
	}
	return
}

type CardMsg struct {
	*Message
}

func (text *CardMsg) SendMsg() (res *SendResult, err error) {
	res = new(SendResult)
	err = text.Message.CheckParams()
	if err != nil {
		log.Errorf("参数校验不合法 err(%+v)", err)
		return
	}
	res.isSuccess, err = Send(text.Sender, text.Receiver, "卡片消息:"+text.Content)
	if err != nil {
		log.Errorf("CardMsg err(%+v)", err)
		return
	}
	return
}

type VideoMsg struct {
	*Message
}

func (text *VideoMsg) SendMsg() (res *SendResult, err error) {
	res = new(SendResult)
	err = text.Message.CheckParams()
	if err != nil {
		log.Errorf("参数校验不合法 err(%+v)", err)
		return
	}
	res.isSuccess, err = Send(text.Sender, text.Receiver, "视频消息:"+text.Content)
	if err != nil {
		log.Errorf("sendMsg err(%+v)", err)
		return
	}
	return
}

type MessageFactory struct {
}

func (factory *MessageFactory) MessageFactory(message *Message, tpy int) SendMsg {
	msg := message
	switch tpy {
	case TextType:
		return &TextMsg{msg}
	case CardType:
		return &CardMsg{msg}
	case PictureType:
		return &PictureMsg{msg}
	case VideoType:
		return &VideoMsg{msg}
	default:
		return nil
	}
	return nil
}

func main() {
	// 客户端代码
	message := &Message{
		Content:  "在吗",
		Sender:   "张三",
		Receiver: "李四",
	}

	messageFactory := &MessageFactory{}
	res := messageFactory.MessageFactory(message, 2)
	result, err := res.SendMsg()
	if err != nil {
		log.Errorf("err(%+v)", err)
	}

	if result.isSuccess {
		fmt.Println("消息发送成功")
	} else {
		fmt.Println("消息发送失败")
	}
}

简单工程的使用场景

(1)对象的创建过程(实例化)很复杂,需要初始化很多参数,比如查询数据库等

(2)子类有相同的属性和方法

简单工厂的优缺点 

优点

1、解耦:把对象的创建和使用分开

2、统一创建对象,方便管理

缺点

1、增加新产品时还是需要修改工厂类的代码,违背了“开闭原则”。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值