go设计模式之抽象工厂模式

抽象工厂模式

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

工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问题,但由于工厂方法模式中的每个工厂只生产一类产品,可能会导致系统中存在大量的工厂类,势必会增加系统的开销。此时,我们可以考虑将一些相关的产品组成一个“产品族”,由同一个工厂来统一生产

抽象工厂模式(Abstract Factory Pattern):提供一个接口,用于创建一系列相关或相互依赖对象的家族,而无须指定它们具体的类。

在工厂方法模式中具体工厂负责生产具体的产品,每一个具体工厂对应一种具体产品,工厂方法也具有唯一性,一般情况下,一个具体工厂中只有一个工厂方法或者一组重载的工厂方法。但是有时候我们需要一个工厂可以提供多个产品对象,而不是单一的产品对象。

  • 产品等级结构:产品等级结构即产品的继承结构,如一个抽象类是电视机,其子类有海尔电视机、海信电视机、TCL电视机,则抽象电视机与具体品牌的电视机之间构成了一个产品等级结构,抽象电视机是父类,而具体品牌的电视机是其子类。
  • 产品族:在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品,如海尔电器工厂生产的海尔电视机、海尔电冰箱,海尔电视机位于电视机产品等级结构中,海尔电冰箱位于电冰箱产品等级结构中。

当系统所提供的工厂所需生产的具体产品并不是一个简单的对象,而是多个位于不同产品等级结构中属于不同类型的具体产品时需要使用抽象工厂模式。

抽象工厂模式与工厂方法模式最大的区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则需要面对多个产品等级结构,一个工厂等级结构可以负责多个不同产品等级结构中的产品对象的创建。

工厂模式的退化

当抽象工厂模式中每一个具体工厂类只创建一个产品对象,也就是只存在一个产品等级结构时,抽象工厂模式退化成工厂方法模式;当工厂方法模式中抽象工厂与具体工厂合并,提供一个统一的工厂来创建产品对象,并将创建对象的工厂方法设计为静态方法时,工厂方法模式退化成简单工厂模式。

参与者

  • AbstractFactory

    声明一个创建抽象产品对象的操作接口。

  • ConcreteFactory

    实现创建具体产品对象的操作。

  • AbstractProduct

    为一类产品对象声明一个接口。

  • ConcreteProduct

    定义一个将被相应的具体工厂创建的产品对象。
    实现AbstractProduct接口。

  • Client

    仅使用由AbstractFactory和AbstractProduct类声明的接口。

案例1

场景:

如果你想要购买一组运动装备,需要购买鞋子和帽子,有adidas和nike品牌。相信你会想去购买同一品牌的商品, 这样商品之间能够互相搭配起来。

  • 抽象工厂接口:ISportsFactory
  • 具体工厂:AdidasFactory、NikeFactory
  • 抽象产品:IShoe、IHat
  • 具体产品:AdidasShoe、AdidaHat、NikeShoe、NikeHat

在这里插入图片描述

抽象产品

iHat.go

package maintype IHat interface {setLogo(logo string)setColor(color string)getLogo() stringgetColor() string
}

iShoe.go

package maintype IShoe interface {setLogo(logo string)setSize(size int)getLogo() stringgetSize() int
}

具体产品

adidasHat.go

package maintype AdidasHat struct {logo stringcolor string
}func (a *AdidasHat) setLogo(logo string) {a.logo = logo
}func (a *AdidasHat) getLogo() string {return a.logo
}func (a *AdidasHat) setColor(color string) {a.color = color
}func (a *AdidasHat) getColor() string {return a.color
}

adidasShoe.go

package maintype AdidasShoe struct {logo stringsize int
}func (a *AdidasShoe) setLogo(logo string) {a.logo = logo
}func (a *AdidasShoe) getLogo() string {return a.logo
}func (a *AdidasShoe) setSize(size int) {a.size = size
}func (a *AdidasShoe) getSize() int {return a.size
}

nikeHat.go

package maintype NikeHat struct {logo  stringcolor string
}func (n *NikeHat) setLogo(logo string) {n.logo = logo
}func (n *NikeHat) getLogo() string {return n.logo
}func (n *NikeHat) setColor(color string) {n.color = color
}func (n *NikeHat) getColor() string {return n.color
}

nikeShoe.go

package maintype NikesShoe struct {logo stringsize int
}func (n *NikesShoe) setLogo(logo string) {n.logo = logo
}func (n *NikesShoe) getLogo() string {return n.logo
}func (n *NikesShoe) setSize(size int) {n.size = size
}func (n *NikesShoe) getSize() int {return n.size
}

抽象工厂

package maintype ISportsFactory interface {makeShoe() IShoemakeHat() IHat
}func GetSportsFactory(brand string) ISportsFactory {if brand == "adidas" {return &AdidasFactory{}}if brand == "nike" {return &NikeFactory{}}return nil
}

具体工厂

adidasFactory.go

package maintype AdidasFactory struct {
}func (a *AdidasFactory) makeShoe() IShoe {return &AdidasShoe{logo: "adidas",size: 42,}
}func (a *AdidasFactory) makeHat() IHat {return &AdidasHat{logo:  "adidas",color: "blue",}
}

nikeFactory.go

package maintype NikeFactory struct {
}func (n *NikeFactory) makeShoe() IShoe {return &NikesShoe{logo: "nike",size: 42,}
}func (n *NikeFactory) makeHat() IHat {return &AdidasHat{logo:  "nike",color: "red",}
}

客户端

client.go

package mainimport "fmt"func main() {f := GetSportsFactory("nike")nikeshoe := f.makeShoe()fmt.Println(nikeshoe.getLogo())fmt.Println(nikeshoe.getSize())nikehat := f.makeHat()fmt.Println(nikehat.getLogo())fmt.Println(nikehat.getColor())
}

这个案例生产了鞋子、帽子,假如鞋子又分好几种,帽子也分好几种,该如何设计代码结构。

案例2

场景:

根据参数设置创建mq和storage
mq有kafka,pulsar
storage有local,minio

跟上一个例子有点不一样,这里只有一个种类,类似于只有nike品牌,nike的鞋子又有2种。

在这里插入图片描述

抽象产品接口:

type ChunkManager interface {Upload()Download()
}type MsgStream interface {Produce()Consume()
}

具体产品:

type KafkaStream struct {
}func (k *KafkaStream) Produce() {fmt.Println("Kafka produce")
}func (k *KafkaStream) Consume() {fmt.Println("Kafka Consume")
}type PulsarStream struct {
}func (p *PulsarStream) Produce() {fmt.Println("Pulsar produce")
}func (p *PulsarStream) Consume() {fmt.Println("Pulsar Consume")
}

每个产品类别的工厂

chunk:

type ChunkFactory interface {NewChunk() ChunkManager
}type ChunkFactoryImpl struct {chunkType string
}func (ck *ChunkFactoryImpl) NewChunk() ChunkManager {if ck.chunkType == "local" {return &LocalChunkManager{}}if ck.chunkType == "minio" {return &MinioChunkManager{}}return nil
}

mq:

type Mqfactory interface {NewMQ() MsgStream
}type MqfactoryImpl struct {mqType string
}func (mq *MqfactoryImpl) NewMQ() MsgStream {if mq.mqType == "kafka" {return &KafkaStream{}}if mq.mqType == "pulsar" {return &PulsarStream{}}return nil
}

抽象工厂

type Factory interface {Init(mqType string, chunkType string)MakeMq() MsgStreamMakeChunk() ChunkManager
}

具体工厂

因为只有一个类别,就用defaultFactory命名

type DefaultFactory struct {chunkFactory ChunkFactorymqfactory    Mqfactory
}func NewDefaultFactory() Factory{return &DefaultFactory{}
}func (d *DefaultFactory) Init(mqType string, chunkType string) {d.chunkFactory = &ChunkFactoryImpl{chunkType: chunkType,}d.mqfactory = &MqfactoryImpl{mqType: mqType,}
}func (d *DefaultFactory) MakeMq() MsgStream {return d.mqfactory.NewMQ()
}func (d *DefaultFactory) MakeChunk() ChunkManager {return d.chunkFactory.NewChunk()
}

客户端:

func main() {f := NewDefaultFactory()f.Init("kafka", "minio")k := f.MakeMq()k.Produce()m := f.MakeChunk()m.Upload()
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/652322.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

巴特沃斯滤波原理及代码实现(matlab详细过程版)

目录 一、算法原理1、原理概述2、参考文献 二、代码实现三、结果展示 本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫与GPT。 一、算法原理 1、原理概述 巴特沃斯滤波器(Butterworth filt…

12 c++版本的坦克大战

前言 呵呵 这大概是 大学里面的 c 贪吃蛇了吧 有一些 面向对象的理解, 但是不多 这里 具体的实现 就不赘述, 仅仅是 发一下代码 以及 具体的使用 坦克大战 #include<iostream> #include<windows.h> #include<conio.h> #include<ctime> #include…

【数据结构与算法】:手搓顺序表(Python篇)

文章目录 一、顺序表的概念二、顺序表的实现1. 顺序表的创建1.1 扩容1.2 整体建立顺序表 2. 顺序表的基本运算算法2.1 顺序表的添加&#xff08;尾插&#xff09;2.2 指定位置插入2.3 指定位置删除2.4 顺序表的查找2.5 顺序表元素的索引访问2.6 顺序表元素的修改2.7 顺序表长度…

Ubuntu 安装遇到 Out of memory

文章目录 应该是RAM的问题降低显卡的RAM使用降低到可兼容的版本然后更新到最新版WIFI接收器不兼容&#xff08;WIFI接收器太新&#xff09;&#xff0c;使用手机连线热点&#xff0c;更新版本后即可用 应该是RAM的问题 降低显卡的RAM使用 YTB:How to fix “Error: Out of Mem…

xfce4 panel 不能显示QQ,钉钉的状态图标

有一段时间不能显示了&#xff0c;之前刚装完系统的时候很长时间内都是好的&#xff0c;所以刚开始肯定是支持显示这些状态图标的。就是因为不能显示的原因&#xff0c;所以还装了lxQt桌面&#xff0c;这个桌面确实不错。不过还是有时会怀念xfce4&#xff0c;想看看能不能解决这…

中电金信:向“新”而行——探索融合架构的项目管理在保险行业的应用

近年来&#xff0c;险企在政策推动、市场牵引、自身发展、新技术应用日趋成熟等内外部因素的驱动下&#xff0c;积极投身到数字化转型的浪潮中。在拜访各类保险客户和合作项目的过程中&#xff0c;我们发现不少险企在数字化转型中或多或少都面临着战略如何落地、技术如何承接和…

Java根据模板动态生成Pdf(添加页码、文件加密、Spire免费版本10页之后无法显示问题、嵌入图片添加公章、转Base64)

Java根据模板动态生成Pdf&#xff1a;添加页码、文件加密、Spire免费版本10页之后无法显示问题、嵌入图片添加公章、转Base64 引言【Java根据模板动态生成Pdf资源地址】示例一&#xff1a;动态生成带页码的PDF报告示例二&#xff1a;加密PDF以保护敏感信息示例三&#xff1a;应…

echarts地图叠加百度地图底板实现数据可视化

这里写自定义目录标题 echarts地图叠加百度地图实现数据可视化echarts地图叠加百度地图实现数据可视化 实现数据可视化时,个别情况下需要在地图上实现数据的可视化,echarts加载geojson数据可以实现以地图形式展示数据,例如分层设色或者鼠标hover展示指标值,但如果要将echa…

Electron+Vue3+ElectronForge整合 - 打包时整合 -分步打包

说明 本文介绍一下 Electron Vue3 的打包整合的基本操作。实现的效果是 &#xff1a; 1、一个正常的Vue3项目&#xff1b; 2、整合加入 Electron 框架 &#xff1a;开发时 Electron 加载的是开发的vue项目&#xff1b; 3、完成打包时整合&#xff1a;3.1 先完成vue3项目的正常…

c语言指针的应用场景

​ 1.什么是指针&#xff1f; 当我们提起指针的时候&#xff0c;可能第一反应会露出惊喜的表情 &#xff08;但是我们其实没必要那么慌&#xff0c;因为当我们随着我们学习的越来越深入就会发现&#xff0c;指针虽然看起来难&#xff0c;实际上也不怎么简单。哈哈哈开玩笑的&a…

DataX数据采集流程(项目)

目录 1.CDH介绍 2.ClouderaManager架构 3.服务器 4.dataX架构 5.Datax数据处理流程 6.DataX的使用说明 7.Mysql数据切割 8.Mysql数据导入HDFS 9.查询站点 站点页面如下&#xff0c;可进一步查询导入的数据内容 10.dataX-Web访问页面 创建数据库连接 1.CDH介绍 --(…

BUUCTF--web(1)

1、[极客大挑战 2019]Http1 1.http报文请求&#xff1a; 1、请求行&#xff1a; 第一部分是请求方法&#xff0c;常见包括GET、POST、OPTIONS&#xff08;我目前还没有见过我是菜鸡&#xff09; 第二部分是url 第三部分是HTTP协议(http(Hypertext transfer protocol)超文本传…