go设计模式之工厂方法模式

news2025/1/15 16:51:18

工厂方法模式

什么是工厂方法模式

工厂方法模式是一种创建型设计模式,它定义了一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化推迟到其子类。

这个接口就是工厂接口,子类就是具体工厂类,而需要创建的对象就是产品对象。客户端代码只需要调用工厂接口的方法,而无需关心具体的产品对象是如何创建的。

用于创建对象的过程中将实例化的逻辑封装在一个工厂方法中。

把被创建的对象称为“产品”,把创建产品的对象称为“工厂”。

在 Go 语言中,工厂方法模式经常被用于对象的创建和初始化。

工厂方法模式的主要优点有:

  • **用户无需关心产品的具体创建细节。**用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程(对创建过程复杂的对象很有作用);

  • 解耦。避免创建者和具体产品之间的紧密耦合。

  • 开闭原则。 无需更改现有客户端代码, 你就可以在程序中引入新的产品类型。;

其缺点是

  • **引入很多新的子类。**应用工厂方法模式需要引入许多新的子类, 代码可能会因此变得更复杂。

角色

工厂方法模式包含四个主要角色:

  • 抽象产品类(Product)
  • 具体产品类(ConcreteProduct)
  • 抽象工厂接口(Creator)
  • 具体工厂类(ConcreteCreator)

抽象产品类定义产品功能接口。

具体产品类实现Product接口。

抽象工厂类声明工厂方法,定义了创建产品的接口。

具体工厂类实现Creator接口,返回ConcreteProduct。

工厂方法代码

工厂方法模式举例

场景:

创建狗子的案例:

创建狗子,狗子有泰迪、柴犬,以后可能会增加比熊。

注意这里就只有一种类型,就是狗子,没有猫子这个种类。

创建狗子的接口工厂IDogFactory(接口MakeDogs(),返回产品接口)
创建狗子具体工厂DogFactory(实现IDogFactory接口)
狗子接口IDog(sleep()、run(),定义产品功能)
泰迪Teddy、柴犬ChaiDog(具体的狗子)

在这里插入图片描述

抽象产品类:

// idog.go
type IDog interface {
	Sleep()
	Run()
}

具体产品类:

柴犬:

// caidog.go
// 柴犬
type ChaiDog struct {
}

func (c ChaiDog) Sleep() {
	fmt.Println("睡觉")
}

func (c ChaiDog) Run() {
	fmt.Println("奔跑")
}

泰迪:

// teddy.go
// 泰迪
type Teddy struct {
}

func (t Teddy) Sleep() {
	fmt.Println("睡觉")
}

func (t Teddy) Run() {
	fmt.Println("奔跑")
}

抽象工厂类(接口工厂):

创建狗子的抽象接口

// factory.go
type IDogFactory interface {
	MakeDogs(dogType string) IDog
}

具体工厂类:

// dogfactory.go
type DogFactory struct {
}

// 提供一个方法实例化工厂
func NewDogFactory() Factory {
	return &DogFactory{}
}

// 工厂方法,这是一个特殊的方法,用来创建不同的狗子
func (d *DogFactory) MakeDog(dogType string) IDog {
	switch dogType {
	case "teddy":
		return &Teddy{name: dogType,
			age: 2,
		}
	case "chaidog":
		return &ChaiDog{name: dogType,
			age: 2,
		}
	}
	return nil
}

场景类:

// client.go
func main() {
	// 创建一个工厂
	f := example.NewFactory()
    // 传入teddy,创建对应的狗子
	teddyDog := f.MakeDog("teddy")
	teddyDog.Sleep()
	teddyDog.Run()
    // 传入chaidog,创建对应的狗子
	cDog := f.MakeDog("chaidog")
	cDog.Sleep()
	cDog.Run()
}

当想加入一个新的产品,例如柯基,添加一个柯基产品子类, 然后重写其工厂方法即可。

简单工厂方法代码

缩小为简单工厂模式。

一个模块仅需要一个工厂类,就没有必要把它实例化出来。java使用静态方法就可以了。

场景:

创建狗子的案例:

创建狗子,狗子有泰迪、柴犬,以后可能会增加比熊。

去掉了工厂接口。

创建狗子的具体工厂DogFactory
狗子接口IDog(sleep()、run(),定义产品功能)
泰迪Teddy、柴犬ChaiDog(具体的狗子)

在这里插入图片描述

抽象产品类:

// idog.go
type IDog interface {
	Sleep()
	Run()
}

具体产品类:

柴犬:

// caidog.go
// 柴犬
type ChaiDog struct {
}

func (c ChaiDog) Sleep() {
	fmt.Println("睡觉")
}

func (c ChaiDog) Run() {
	fmt.Println("奔跑")
}

泰迪:

// teddy.go
// 泰迪
type Teddy struct {
}

func (t Teddy) Sleep() {
	fmt.Println("睡觉")
}

func (t Teddy) Run() {
	fmt.Println("奔跑")
}

抽象工厂类(接口工厂):

去掉。

具体工厂类:

// dogfactory.go
// 工厂方法,这是一个特殊的方法,用来创建不同的狗子
func MakeDogs(dogType string) IDog {
	if dogType == "teddy" {
		return &Teddy{}
	}
	if dogType == "chaidog" {
		return &ChaiDog{}
	}
	return nil
}

场景类:

// client.go
func main() {
	teddyDog := example.MakeDog("teddy")
	teddyDog.Sleep()
	teddyDog.Run()
	cDog := example.MakeDog("chaidog")
	cDog.Sleep()
	cDog.Run()
}

工厂方法代码(升级)

升级为多个具体工厂类。

假如有1个产品类有5个具体实现,每个实现类的初始化方法都不相同,如果写在一个工厂方法中,会导致这个方法巨大无比。

为每一个产品定义一个ConcreteCreator。

创建狗子的案例:

创建狗子的接口工厂Factory(MakeDogs())

创建泰迪狗子的具体工厂ChaiDogFactory(实现接口Factory)

创建泰迪柴犬的具体工厂TeddyFactory(实现接口Factory)

狗子接口(sleep()、run())
泰迪、柴犬(具体的狗子)

在这里插入图片描述

接口工厂类:

// factory.go
type Factory interface {
	// 无需再传递参数了
	MakeDog() IDog
}

抽象产品类:

// idog.go
type IDog interface {
	Sleep()
	Run()
}

具体产品类:

柴犬:

// caidog.go
// 柴犬
type ChaiDog struct {
}

func (c ChaiDog) Sleep() {
	fmt.Println("睡觉")
}

func (c ChaiDog) Run() {
	fmt.Println("奔跑")
}

泰迪:

// teddy.go
// 泰迪
type Teddy struct {
}

func (t Teddy) Sleep() {
	fmt.Println("睡觉")
}

func (t Teddy) Run() {
	fmt.Println("奔跑")
}

具体工厂:

// teddyfactory.go
// 创建泰迪的具体工厂
type TeddyFactory struct {
}

func NewTeddyFactory() Factory {
	return &TeddyFactory{}
}

func (d *TeddyFactory) MakeDog() IDog {
	return &Teddy{name: "tom",
		age: 2,
	}
}

// caidogfactory.go
// 创建柴犬的具体工厂
type ChaiDogFactory struct {
}

func NewChaiDogFactory() Factory {
	return &ChaiDogFactory{}
}

func (d *ChaiDogFactory) MakeDog() IDog {
	return &ChaiDog{name: "kate",
		age: 2,
	}
}

场景类:

// client.go
func main() {
	cf := example.NewChaiDogFactory()
	teddyDog := cf.MakeDog()
	teddyDog.Sleep()
	teddyDog.Run()
	tf := example.NewTeddyFactory()
	caiDog := tf.MakeDog()
	caiDog.Sleep()
	caiDog.Run()
}

如果要扩展一个产品类,需要建立一个相应的工厂类,增加了扩展的难度。

在复杂的应用中一般才用多工厂的方法,然后再增加一个协调类,避免调用者与各个子工厂交流。

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

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

相关文章

盛水最多的容器 ---- 双指针

题目链接 题目: 分析: 最大容积 即使就是最大面积, 长为下标之差, 宽为两下标对应值的最小值解法一: 暴力枚举: 将每两个数之间的面积都求出来, 找最大值, 时间复杂度较高解法二: 假设我们的数组是[6, 2, 5, 4], 我们先假设最左边和最右边, 即6 和 4 之间是最大面积长a*宽b此…

便携式应急指挥箱规格参数

概况: 微缩型的无线视频音频传输的机动挥所。体积小、重量轻、公配电方便、携带便携、功能齐全。可进行单兵作战,通过此无线音频视频传输的指挥箱能完成现场图像、语音、数据的采集等功能,可以通过5G/4G/WIFI等多种无线网络完成传输的需求,或…

和鲸科技出席第五届空间数据智能学术会议,执行总裁殷自强受邀发表主题报告

4月26日,由 ACM SIGSPATIAL 中国分会、ACM SIGMOD 中国分会主办的第五届空间数据智能学术会议(SpatialDI 2024,下简称“会议”)在南京盛大开幕。本次会议特邀李清泉院士、周成虎院士、丛高教授、谢炯博士、张雪英教授等国内外知名…

流量网关与服务网关的区别:(面试题,掌握)

流量网关:(如Nignx,OpenResty,Kong)是指提供全局性的、与后端业务应用无关的策略,例如 HTTPS证书认证、Web防火墙、全局流量监控,黑白名单等。 服务网关:(如Spring Clou…

通义灵码-IDEA的使用教程

通义灵码-IDEA的使用教程 1、通义灵码是什么? 通义灵码,是阿里云出品的一款基于通义大模型的智能编码辅助工具,提供行级/函数级实时续写、自然语言生成代码、单元测试生成、代码注释生成、代码解释、研发智能问答、异常报错排查等能力&#…

受尽折磨的ai剪辑视频心酸之路

因为公司需要剪辑好多视频~我每天不断手动剪啊剪啊手都剪麻 有天老板跟我说了句人家好多ai剪辑你能不能搞到一个,多少钱你在说。 我心想这不是我的强项么?白嫖界的天花板,我就拦下了这个活~于是我上班不是在找软件就是在逛论坛路上&#xff0…

【漏洞复现】润乾报表InputServlet13文件读取漏洞

漏洞描述: 润乾报表是一款功能全面且性能卓越的报表产品。它专注于企业级BI产品的研发和推广,通过提供丰富的报表功能和高效的开发工具,帮助用户提升图表的开发效率,节省成本。 润乾报表InputServlet13接口存在文件读取漏洞&…

数据结构 - 链表详解一 - 链表的介绍

一. 为什么要学习链表 我们已经学习了顺序表了,在学习的时候发现顺序表的功能很多,所以我们为什么还要学习链表呢,学习链表有什么用吗? 下面我将通过几个方面去研究一下 1. 动态数据操作 顺序表(如数组)通…

回溯-单词搜索

给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相…

力扣刷题总结——栈和队列

刷完栈和队列,对STL的内容有了更加深刻的认识。 STL中栈往往不被归类为容器,而被归类为container adapter(容器适配器) 栈的内部结构,栈的底层实现可以是 vector,deque,list 都是可以的&#xf…

ANSYS WB DesignModeler 概述

Workbench 在进行有限元分析之前,一般需要创建或导入模型。创建模型时一般会用到 DesignModeler 组件,在该组件中可以进行2D和3D模型的创建。 本章主要讲述 DesignModeler 的基础操作,包括启动、图形界面、图形选择和右键快捷菜单。 1.启动 DesignModel…

【数字电路与系统】【北京航空航天大学】实验:时序逻辑设计——三色灯开关(二)、需求分析和系统设计

本次实验(一)见博客:【数字电路与系统】【北京航空航天大学】实验:时序逻辑设计——三色灯开关(一)、实验指导书 说明:本次实验的代码使用verilog编写,文章中为阅读方便&#xff0c…

OGG extract进程占据大量虚拟内存导致服务器内存异常增长分析

现象 oracle服务器一节点内存,一个月来持续升高,近一月上涨10%左右。 问题分析 OS内存使用情况 使用内存最大的10个进程如下,PID为279417占用最大的内存。 查询279417,发现是ogg相关进程。 发现ogg的extract进程占用了大量的虚拟内…

Lagent AgentLego 智能体应用搭建-笔记六

本次课程由Lagent&AgentLego 核心贡献者樊奇老师讲解【Lagent & AgentLego 智能体应用搭建】课程 课程视频:https://www.bilibili.com/video/BV1Xt4217728/ 课程文档:https://github.com/InternLM/Tutorial/tree/camp2/agent 大语言模型的局限…

E4980A是德科技E4980A精密LCR表

181/2461/8938产品概述: Keysight E4980A 精密 LCR 表为各种元件测量提供了精度、速度和多功能性的最佳组合。E4980A 在低阻抗和高阻抗范围内提供快速测量速度和出色的性能,是元件和材料的一般研发和制造测试的终极工具。LAN、USB 和 GPIB PC 连接可提高…

Openharmony - 设备异常关机Power Down问题分析

By: fulinux E-mail: fulinux@sina.com Blog: https://blog.csdn.net/fulinus 喜欢的盆友欢迎点赞和订阅! 你的喜欢就是我写作的动力! 目录 1.问题描述1.1出现power down的原因1.1.1硬件故障或信号1.1.2软件错误或系统崩溃2.抓日志信息2.1.抓日志方法2.2.问题初步分析3.问题排…

前后端分离实践:使用 React 和 Express 搭建完整登录注册流程

文章目录 概要整体架构流程技术名词解释ReactExpressReact RouterAnt Design 技术细节前端设计后端逻辑数据交互 小结 概要 本项目是一个基于React和Express的简单登录注册系统。通过前后端分离的方式,实现了用户的注册、登录和查看用户列表等功能。前端使用React框…

学习通刷课免费,成绩又高的方法(超详细)

文章目录 概要整体架构流程 概要 我们在大学的时候有好多课程都是线上的水课,这时我们需要刷课又不想花钱怎么办,这篇文章推荐三个脚本配合使用,成绩还不错亲试; 整体架构流程 1.我们先找到浏览器的扩展程序 2.点击获取扩展 …

【vscode】2024最新!vscode设置默认终端为git bash

小tian最近电脑系统重装,刚好可以重新配置一下前端环境和工具,以此专栏记录一下前端工具配置和环境相关内容。 vscode如何设置默认终端为git bash? 首先,当然是你要先装好git啦 git怎么安装,废话不多说,&…

SaTokenException: 非Web上下文无法获取Request问题解决

最近在学定时任务,需要获取到当前用户信息然后再定时任务方法中取出当前用户信息,刚开始使用的是StpUtil.getTokenInfo()或者 StpUtil.getLoginId()这类方法,但是报错了,哈哈哈哈~ 其实看源代码就知道了,需要提供Http…