【设计模式】已有工厂模式,抽象工厂改进了哪些?

抽象工厂模式是创建型的设计模式

GoF定义:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

优点和上一篇工厂模式提到的一样,那你会说都一样,为什么需要这个模式呢,所以肯定有不一样的地方。

业务是非常复杂的,一个流程会牵涉到多个对象,分多个对象就是为了体现单一职责设计思想,所以不会把一个流程中所有的功能都放到一个对象中。

抽象工厂模式就是为了解决这个问题的,它可以返回多个对象。具体来看示例。

场景

消息发送系统,需要支持 短信、邮件、APP推送、微信小程序订阅消息、微信服务号模板消息。

需要对接 AliYun、BaiduYun、容联云、微信。

go 复制代码
package main  
  
import "fmt"  

type ISms interface {
	Sms(msg string) (string, error)
}

type IAppPush interface {
	AppPush(msg string) (string, error)
}

type IEmail interface {
	Email(msg string) (string, error)
}

type IMiniProgramSubscribeMsg interface {
	SubscribeMsg(msg string) (string, error)
}

type IOfficeWeChatTemplateMsg interface {
	TemplateMsg(msg string) (string, error)
}

type IMessage interface {
	ISms
	IAppPush
	IEmail
	IMiniProgramSubscribeMsg
	IOfficeWeChatTemplateMsg
}

// AliYun 阿里云
type AliYun struct {
}

func NewAliYun() IMessage {
	return &AliYun{}
}

func (a *AliYun) Sms(msg string) (string, error) {
	return "AliYun sms send success, content: " + msg, nil
}

func (a *AliYun) AppPush(msg string) (string, error) {
	return "AliYun app push send success, content: " + msg, nil
}

func (a *AliYun) Email(msg string) (string, error) {
	return "AliYun email send success, content: " + msg, nil
}

func (a *AliYun) SubscribeMsg(msg string) (string, error) {
	return "", fmt.Errorf("miniProgram subscribe msg not support")
}

func (a *AliYun) TemplateMsg(msg string) (string, error) {
	return "", fmt.Errorf("office wechat not support")
}

// MiniProgram 小程序
type MiniProgram struct {
}

func NewMiniProgram() IMessage {
	return &MiniProgram{}
}

func (m *MiniProgram) Sms(msg string) (string, error) {
	return "", fmt.Errorf("sms not support")
}

func (m *MiniProgram) Email(msg string) (string, error) {
	return "", fmt.Errorf("email not support")
}

func (m *MiniProgram) AppPush(msg string) (string, error) {
	return "", fmt.Errorf("app push not support")
}

func (m *MiniProgram) SubscribeMsg(msg string) (string, error) {
	return "MiniProgram subscribe msg send success, content:" + msg, nil
}

func (m *MiniProgram) TemplateMsg(msg string) (string, error) {
	return "", fmt.Errorf("office wechat template msg not support")
}

type IMessageFactory interface {
	CreateSms() ISms
	CreateAppPush() IAppPush
	CreateEmail() IEmail
	CreateMiniProgramSubscribeMsg() IMiniProgramSubscribeMsg
	CreateIOfficeWeChatTemplateMsg() IOfficeWeChatTemplateMsg
}

// AliYunFactory 阿里云工厂
type AliYunFactory struct{}

func NewAliYunFactory() IMessageFactory {
	return &AliYunFactory{}
}

func (a *AliYunFactory) CreateSms() ISms {
	return NewAliYun()
}

func (a *AliYunFactory) CreateAppPush() IAppPush {
	return NewAliYun()
}

func (a *AliYunFactory) CreateEmail() IEmail {
	return NewAliYun()
}
func (a *AliYunFactory) CreateMiniProgramSubscribeMsg() IMiniProgramSubscribeMsg {
	return NewAliYun()
}

func (a *AliYunFactory) CreateIOfficeWeChatTemplateMsg() IOfficeWeChatTemplateMsg {
	return NewAliYun()
}

// MiniProgramFactory 小程序工厂
type MiniProgramFactory struct{}

func NewMiniProgramFactory() IMessageFactory {
	return &MiniProgramFactory{}
}

func (m *MiniProgramFactory) CreateSms() ISms {
	return NewMiniProgram()
}

func (m *MiniProgramFactory) CreateAppPush() IAppPush {
	return NewMiniProgram()
}

func (m *MiniProgramFactory) CreateEmail() IEmail {
	return NewMiniProgram()
}

func (m *MiniProgramFactory) CreateMiniProgramSubscribeMsg() IMiniProgramSubscribeMsg {
	return NewMiniProgram()
}

func (m *MiniProgramFactory) CreateIOfficeWeChatTemplateMsg() IOfficeWeChatTemplateMsg {
	return NewMiniProgram()
}

func main() {  
    message := "message content"  
    aliYunFactory := NewAliYunFactory()  
    fmt.Println(aliYunFactory.CreateSms().Sms(message))  
    fmt.Println(aliYunFactory.CreateAppPush().AppPush(message))  
    fmt.Println(aliYunFactory.CreateMiniProgramSubscribeMsg().SubscribeMsg(message))  
  
    baiduFactory := NewMiniProgramFactory()  
    fmt.Println(baiduFactory.CreateMiniProgramSubscribeMsg().SubscribeMsg(message))  
    fmt.Println(baiduFactory.CreateSms().Sms(message))  
}

NewAliYunFactory NewMiniProgramFactory 分别实现了 aliyun 的短信、邮件、APP推送、微信小程序订阅消息、微信服务号模板消息 对象创建 miniProgram 的短信、邮件、APP推送、微信小程序订阅消息、微信服务号模板消息 对象创建 然后分别调用 对应的方法进行数据发送

总结

看了上述的代码,可能会提出这样的问题 aliYunFactory、 baiduFactory 创建需要自己显示的指名,能否通过业务自动判断需要使用哪个工厂进行对象的创建? 答案是可以的,下面是修改后的代码

go 复制代码
type MessageFactoryFunc func() IMessageFactory  
  
var messageFactoryFuncMap = map[string]MessageFactoryFunc{  
    "aliyun":      NewAliYunFactory,  
    "miniprogram": NewMiniProgramFactory,  
}

func main() {
	message := "message content"  
	messageFactoryFunc := messageFactoryFuncMap["aliyun"]  
	factory := messageFactoryFunc()  
	fmt.Println(factory.CreateSms().Sms(message))  
	fmt.Println(factory.CreateAppPush().AppPush(message))  
	fmt.Println(factory.CreateMiniProgramSubscribeMsg().SubscribeMsg(message))
}

定义了 messageFactoryFuncMap 维护key和工厂方法的映射,这样就可以通过key 动态的创建工厂。

怎么样,有什么感想,我看了之后,感觉比直接写对应的方法实现复杂了不少,但是回过头来想一想,后续若需要新增新的服务商,会很方便。

相关推荐
Asthenia04121 小时前
为什么说MVCC无法彻底解决幻读的问题?
后端
Asthenia04121 小时前
面试官问我:三级缓存可以解决循环依赖的问题,那两级缓存可以解决Spring的循环依赖问题么?是不是无法解决代理对象的问题?
后端
Asthenia04121 小时前
面试复盘:使用 perf top 和火焰图分析程序 CPU 占用率过高
后端
Asthenia04121 小时前
面试复盘:varchar vs char 以及 InnoDB 表大小的性能分析
后端
Asthenia04121 小时前
面试问题解析:InnoDB中NULL值是如何记录和存储的?
后端
Asthenia04121 小时前
面试官问我:TCP发送到IP存在但端口不存在的报文会发生什么?
后端
Asthenia04121 小时前
HTTP 相比 TCP 的好处是什么?
后端
Asthenia04121 小时前
MySQL count(*) 哪个存储引擎更快?为什么 MyISAM 更快?
后端
Asthenia04121 小时前
面试官问我:UDP发送到IP存在但端口不存在的报文会发生什么?
后端
Asthenia04121 小时前
深入理解 TCP backlog 参数:意义、应用场景与 Netty 中的应用
后端