前言
本系列文章将介绍使用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、增加新产品时还是需要修改工厂类的代码,违背了“开闭原则”。