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

news2024/12/23 6:05:18

抽象工厂模式

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

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

抽象工厂模式(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 main

type IHat interface {
	setLogo(logo string)
	setColor(color string)
	getLogo() string
	getColor() string
}

iShoe.go

package main

type IShoe interface {
	setLogo(logo string)
	setSize(size int)
	getLogo() string
	getSize() int
}

具体产品

adidasHat.go

package main

type AdidasHat struct {
	logo string
	color 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 main

type AdidasShoe struct {
	logo string
	size 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 main

type NikeHat struct {
	logo  string
	color 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 main

type NikesShoe struct {
	logo string
	size 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 main

type ISportsFactory interface {
	makeShoe() IShoe
	makeHat() IHat
}

func GetSportsFactory(brand string) ISportsFactory {
	if brand == "adidas" {
		return &AdidasFactory{}
	}

	if brand == "nike" {
		return &NikeFactory{}
	}

	return nil
}

具体工厂

adidasFactory.go

package main

type 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 main

type 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 main

import "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() MsgStream
	MakeChunk() ChunkManager
}

具体工厂

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

type DefaultFactory struct {
	chunkFactory ChunkFactory
	mqfactory    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.coloradmin.cn/o/1627397.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【禅道客户案例】同方智慧能源数智化转型新实践 禅道助力前行

同方智慧能源是同方股份有限公司的骨干企业。依托中核集团、清华大学的科技优势,坚持技术和资源双核驱动,基于30多年行业积淀,面向建筑、交通、工业、北方供热、数据中心等主要用能场景提供设计咨询、产品技术、投资建设、运营服务&#xff0…

每天一题crypto(8)---RSA(相邻素数)

题目: p getPrime(512) q gmpy2.next_prime(p) from Crypto.Util.number import * import gmpy2 flag bNSSCTF{******}p getPrime(512) q gmpy2.next_prime(p) n p*q e 65537 phi (p-1)*(q-1)m bytes_to_long(flag)c pow(m, e, n)print(fn {n}) print(f…

Linux网络编程---多进/线程并发服务器

一、多进程并发服务器 实现一个服务器可以连接多个客户端,每当accept函数等待到客户端进行连接时 就创建一个子进程 思路分析: 核心思路:让accept循环阻塞等待客户端,每当有客户端连接时就fork子进程,让子进程去和客户…

【调研分析】机器视觉及其系统

机器视觉 定义 机器视觉主要利用计算机模拟人的视觉功能,但不仅限于人眼的简单延伸,而是具备人脑的部分功能,即从客观事物的图像中提取信息、进行处理并加以理解,从而应用于实际的检测识别、测量和控制过程。 机器视觉系统组成 …

JavaEE >> Spring Boot(2)

Spring Boot 配置文件 前面的文章已经介绍了 Spring Boot 项目的创建,上文,本文介绍 Spring Boot 的简单进阶使用。 配置文件的作用 项目中的所有重要数据都是在配置文件中配置的,例如: 数据库的连接信息(包括数据…

BossCMS RCE(下)

未授权漏洞 在登录后台的时候通过查看添加用户功能,看能不能挖掘sql注入漏洞,结果发现了个大问题,一个比较好玩的权限逻辑问题。这里添加用户的路由 我们跟进到manager.class.php里面的add()方法,这里先into::basc_class(admin)&…

DS进阶:并查集

一、并查集的原理 在一些应用问题中,需要将n个不同的元素划分成一些不相交的集合。开始时,每个元素自成一个单元素集合,然后按一定的规律将归于同一组元素的集合合并。在此过程中要反复用到查询某一个元素归属于那个集合的运算。适合于描述这…

局部多项式近似与 AMPM 算法

kappa3; %已在您的代码中定义% 定义窗口大小 windowSize (2*kappa1);% 初始化梯度估计值 [rows, cols] size(wrappedPhase); phi_y zeros(rows, cols); phi_x zeros(rows, cols);% 遍历每个窗口 for m 1kappa:rows-kappafor n 1kappa:cols-kappa% 提取局部窗口Z_mn wrap…

python 使用flask_httpauth和pyjwt实现登录权限控制

最近需要用到,学习了一下记录 首先安装依赖 pip install Flask-HTTPAuth pyjwt passlib Welcome to Flask-HTTPAuth’s documentation! — Flask-HTTPAuth documentation Welcome to PyJWT — PyJWT 2.8.0 documentation Passlib 1.7.4 documentation — Passl…

【代码随想录刷题记录】LeetCode27移除元素

题目地址 1. 思路 1.1 基本思路及代码的初步实现 基本思路大体上和卡尔老师的想法是一致的,详见代码随想录:数组:移除元素,暴力法大家都能想到,我这里写一下算法时间复杂度为 O ( n ) O(n) O(n)时候的思路&#xff…

短视频矩阵营销系统 poihuoqu 任意文件读取漏洞复现

0x01 产品简介 短视频矩阵营销系统是由北京华益云数据科技有限公司开发的一款产品,这家公司专注于抖音短视频矩阵营销系统的研发,致力于为企业提供全方位的短视频营销解决方案。华益云抖销短视频矩阵系统可以帮助企业快速搭建多个短视频账号,实现内容的批量制作和发布,提高…

ShardingSphere 5.x 系列【25】 数据分片原理之 SQL 解析

有道无术,术尚可求,有术无道,止于术。 本系列Spring Boot 版本 3.1.0 本系列ShardingSphere 版本 5.4.0 源码地址:https://gitee.com/pearl-organization/study-sharding-sphere-demo 文章目录 1. 分片执行流程1.1 Simple Push Down1.2 SQL Federation2. SQL 解析2.1 解析…

SystemUI KeyButtonView setDarkIntensity 解析

继承自 ImageView KeyButtonDrawable intensity为0时按键颜色为白色。 intensity为1时黑色为的调用堆栈: java.lang.NullPointerException: Attempt to invoke virtual method int java.lang.String.length() on a null object referenceat com.android.systemui.…

嵌入式学习Day18

一、输入两个数,实现排序 代码: #!/bin/bashread -p "please enter n m:" n m if [ $n -gt $m ] thentemp$nn$mm$temp fi echo $n $m运行结果 二、输入一个数判断是否水仙花数 代码: echo narcissistic number read -p "p…

店匠科技技术产品闪耀,引领新质生产力发展

在科技飞速发展的今天,新质生产力正成为推动社会进步和经济高质量发展的核心力量。店匠科技,作为一家致力于为全球B2C电商提供产品和技术解决方案的领先企业,其技术产品不仅体现了新质生产力的创新特质,更在推动电商行业转型升级中发挥了重要作用。 新质生产力,以创新为主导,摆…

Java设计模式 _创建型模式_原型模式(Cloneable)

一、原型模式 1、原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能比较好。一般对付出较大代价获取到的实体对象进行克隆操作,可以提升性能。 2、实现思路: (1)、需要克隆的…

macOS 一些系统图标的存放位置 icns

macOS 一些系统图标的存放位置 icns macOS 中有很多好看的图标,有时候就想用一下它,我来告诉你他们的具体位置。 系统图标位置,像各种通用文件类型的图标都在这里面,里面好多高清的系统图标 /System/Library/CoreServices/Core…

济宁市中考报名照片要求及手机拍照采集证件照方法

随着中考报名季的到来,并且进入了中考报名演练阶段,济宁市的广大考生和家长都开始忙碌起来。报名过程中,上传一张符合要求的证件照是必不可少的环节。本文将详细介绍济宁市中考报名照片的具体要求,并提供一些实用的手机拍照采集证…

flutter开发实战-build apk名称及指令abiFilters常用gradle设置

flutter开发实战-build apk名称及指令abiFilters常用gradle设置 最近通过打包flutter build apk lib/main.dart --release,发现apk命名规则需要在build.gradle设置。这里记录一下。 一、apk命名规则 在android/app/build.gradle中需要设置 android.applicationVa…

TinyML之Hello world----基于Arduino Nano 33 BLE Sense Rev2的呼吸灯

早期版本的Hello World 这应该是一个逼格比较高的呼吸灯了,用ML来实现呼吸灯功能,之前已经有大佬发过类似的文章:https://blog.csdn.net/weixin_45116099/article/details/126310816 当前版本的Hello World 这是一个ML的入门例程&#xff…