当前位置: 首页 > article >正文

工厂方法模式和抽象工厂方法模式的battle

1.案例直接上手

在这个案例里面,我们会实现这个普通的工厂方法,并且对比这个普通工厂方法和我们直接创建对象的差别在哪里,为什么需要一个工厂:

下面的这个是我们的这个案例里面涉及到的接口和对应的实现类:

两个发送的方式,一个实现类是使用的邮件的形式,一个实现类使用的短信的方式

image-20250607212502666

下面的这个是我们的工厂,里面有一个方法,负责生产我们的对象:我们使用上面定义的接口进行返回值的接受,因为我们的这个返回值可能是不同的实现类,我们使用他们的共同实现的接口作为返回值的类型;

下面的这个代码的逻辑其实也是非常的简单,就是我们的这个输入的参数类型和我们的邮件一样,这个时候我们创建一个邮件的对象,如果和消息一样,我们创建的就是消息类型的这个对象,否则我们直接返回null即可;

image-20250607212719989

我们写一个测试类进行测试:传入这个mail参数,这个时候返回的就是我们的mail类型对象,调用里面的send方法;

image-20250607212924786

下面的这个是输出的结果,相信大家是很容易理解的:

image-20250607213019705

2.总结思考

上面的这个案例里面,我们定义了一个工厂,但是这个实现的效果显的很low,为什么这样说,因为这个过程我们两行代码就可以搞定;

我们可以直接创建一个mailSender对象,直接调用方法,岂不是更爽???

image-20250607213125368

实现的这个输出的效果完全一致,没有任何的区别:

image-20250607213223407

那么这样的话,我就有问题了,我们的这个工厂方法的优势体现在哪里呢,我们是不是不需要学习这个设计模式了呢,答案肯定是否定的,下面我们开始进行延伸,展示一下这个工厂的优势:

3.工厂的优势

如果这个时候创建200个对象,上面的两个做法的区别其实也不是很大,工厂是produce创建对象,而普通方法是直接new对象即可,调用对应的方法;

可见,这个情境下,我们的工厂方法仍然没有凸显自己的优势,但是如果我告诉你,每一次创建对象之前,我们需要打印“我喜欢学习设计模式”,阁下又应该如何应对呢;

使用普通的方法创建对象,当需要打印这句话的需求提出之后,我们每一次创建对象,都需要去打印这句话,200个对象需要打印200次,这样写的代码就非常的不美观,因为这个重复的内容太多了;

image-20250607213600602

这个时候,我们的工厂方法就凸显了自己的优势:我们只需要在这个工厂方法里面添加一句话,这个时候我们的这个所有的主函数里面的对象调用这个produce的时候就可以打印结果了,而不需要重复200次,这就是提升;从200遍到1遍,这个就提升了不少;

image-20250607213749956

如果这个时候客户又让你把那句话删除掉,这个时候工厂方法只需要删除一个地方,而我们的普通方法全部需要删除;

工厂方法:需要大量的创建对象的时候,使用工厂方法,提高代码的可维护性;

如果我们需要更多的实现类,我们的这个工厂方法也是会凸显优势的,方便对于这个实现类的管理;

4.多个工厂方法的改进

即使如此,我们使用了工厂模式,上面的这个代码依然是可以进行优化和改进的,如下所示,如果我们在这个测试类里面把这个参数传递错误了,对吧,我们的这个用户不小心在这个参数里面mail后面多加上了一个字符,这个时候就会出现无法对应的情况;

image-20250608104728909

下面的这个就是出现的异常,因为我们使用null调用这个send方法了,我们没有找到对应的mail或者是这个sms,这个时候s接收到的就是null,然后使用这个null调用我们的方法肯定就是不可取的了;

image-20250608104903949这个时候,就不得不提我们的这个多个工厂方法了,如下所示:增加工厂方法,意味着我们可以直接调用这个增加的工厂方法:

image-20250608110115363

这样的话,我们的测试类里面不需要进行这个参数的传递的过程,而是可以直接进行我们的新的方法的调用,这样就可以杜绝上面的那个参数传递错误的情况,而是直接调用对应的方法即可:

image-20250608110246072

5.静态工厂方法

上面的这个例子,我们需要先创建对象,然后去调用里面的相关的方法,这个时候我们可以继续优化,把原来的这个换成我们的静态的方法,这样就可以直接使用我们的类调用相关的方法即可,不需要进行这个new对象的操作;

image-20250608110904964

然后我们的这个测试类里面可以直接调用方法,不用创建对象,这个就是我们的静态方法的好处:

image-20250608111012478

6.抽象工厂方法模式

接下来,我们继续扩展,这个时候,如果我们需要在原来的发送邮件,发送信息的基础上面,添加这个发送包裹,我们会如何修改;

如果使用原来的方法,就需要在我们的工厂里面增加方法,然后去定义一个包裹类,实现我们原来定义的接口,但是这样做就违反了我们的开闭原则(测试之后不要再原来的基础上进行修改,可以增加,但是不要动原来的代码);

因此,我们引入了下面的这个抽象工厂方法:

通过下面的这个类图你可以是可以看出来的,我们的这个抽象工厂方法模式在原来的基础上进行了二次封装,定义了新的接口,两个工厂:

1)原来是一个工厂里面两个方法,我们需要增加包裹发送方式的时候,需要在工厂里面添加方法,违反了开闭原则;

2)抽象工厂方法里面,我们定义两个工厂,一个发送方式对应一个工厂,我们需要增加这个新的发送方式的时候,原来的代码都不需要变化,直接添加新的工厂里面实现这个方法即可;

3)这样的话,我们的抽象工厂方法就解决了我们的简单工厂方法的这个违反了开闭原则的问题,提高了代码的封装性和可扩展性;

image-20250608111921886
样的话,我们的抽象工厂方法就解决了我们的简单工厂方法的这个违反了开闭原则的问题,提高了代码的封装性和可扩展性;

相关文章:

工厂方法模式和抽象工厂方法模式的battle

1.案例直接上手 在这个案例里面,我们会实现这个普通的工厂方法,并且对比这个普通工厂方法和我们直接创建对象的差别在哪里,为什么需要一个工厂: 下面的这个是我们的这个案例里面涉及到的接口和对应的实现类: 两个发…...

深入解析 ReentrantLock:原理、公平锁与非公平锁的较量

ReentrantLock 是 Java 中 java.util.concurrent.locks 包下的一个重要类,用于实现线程同步,支持可重入性,并且可以选择公平锁或非公平锁的实现方式。下面将详细介绍 ReentrantLock 的实现原理以及公平锁和非公平锁的区别。 ReentrantLock 实现原理 基本架构 ReentrantLo…...

鸿蒙Navigation路由导航-基本使用介绍

1. Navigation介绍 Navigation组件是路由导航的根视图容器,一般作为Page页面的根容器使用,其内部默认包含了标题栏、内容区和工具栏,其中内容区默认首页显示导航内容(Navigation的子组件)或非首页显示(Nav…...

JavaScript 标签加载

目录 JavaScript 标签加载script 标签的 async 和 defer 属性,分别代表什么,有什么区别1. 普通 script 标签2. async 属性3. defer 属性4. type"module"5. 各种加载方式的对比6. 使用建议 JavaScript 标签加载 script 标签的 async 和 defer …...

「Java基本语法」变量的使用

变量定义 变量是程序中存储数据的容器,用于保存可变的数据值。在Java中,变量必须先声明后使用,声明时需指定变量的数据类型和变量名。 语法 数据类型 变量名 [ 初始值]; 示例:声明与初始化 public class VariableDemo {publi…...

CMS内容管理系统的设计与实现:多站点模式的实现

在一套内容管理系统中,其实有很多站点,比如企业门户网站,产品手册,知识帮助手册等,因此会需要多个站点,甚至PC、mobile、ipad各有一个站点。 每个站点关联的有站点所在目录及所属的域名。 一、站点表设计…...

用鸿蒙HarmonyOS5实现国际象棋小游戏的过程

下面是一个基于鸿蒙OS (HarmonyOS) 的国际象棋小游戏的完整实现代码,使用Java语言和鸿蒙的Ability框架。 1. 项目结构 /src/main/java/com/example/chess/├── MainAbilitySlice.java // 主界面逻辑├── ChessView.java // 游戏视图和逻辑├── …...

ZYNQ学习记录FPGA(二)Verilog语言

一、Verilog简介 1.1 HDL(Hardware Description language) 在解释HDL之前,先来了解一下数字系统设计的流程:逻辑设计 -> 电路实现 -> 系统验证。 逻辑设计又称前端,在这个过程中就需要用到HDL,正文…...

k8s从入门到放弃之Pod的容器探针检测

k8s从入门到放弃之Pod的容器探针检测 在Kubernetes(简称K8s)中,容器探测是指kubelet对容器执行定期诊断的过程,以确保容器中的应用程序处于预期的状态。这些探测是保障应用健康和高可用性的重要机制。Kubernetes提供了两种种类型…...

精益数据分析(98/126):电商转化率优化与网站性能的底层逻辑

精益数据分析(98/126):电商转化率优化与网站性能的底层逻辑 在电子商务领域,转化率与网站性能是决定商业成败的核心指标。今天,我们将深入解析不同类型电商平台的转化率基准,探讨页面加载速度对用户行为的…...

Java中HashMap底层原理深度解析:从数据结构到红黑树优化

一、HashMap概述与核心特性 HashMap作为Java集合框架中最常用的数据结构之一,是基于哈希表的Map接口非同步实现。它允许使用null键和null值(但只能有一个null键),并且不保证映射顺序的恒久不变。与Hashtable相比,Hash…...

【记录坑点问题】IDEA运行:maven-resources-production:XX: OOM: Java heap space

问题:IDEA出现maven-resources-production:operation-service: java.lang.OutOfMemoryError: Java heap space 解决方案:将编译的堆内存增加一点 位置:设置setting-》构建菜单build-》编译器Complier...

【阅读笔记】MemOS: 大语言模型内存增强生成操作系统

核心速览 研究背景 ​​研究问题​​:这篇文章要解决的问题是当前大型语言模型(LLMs)在处理内存方面的局限性。LLMs虽然在语言感知和生成方面表现出色,但缺乏统一的、结构化的内存架构。现有的方法如检索增强生成(RA…...

Java中栈的多种实现类详解

Java中栈的多种实现类详解:Stack、LinkedList与ArrayDeque全方位对比 前言一、Stack类——Java最早的栈实现1.1 Stack类简介1.2 常用方法1.3 优缺点分析 二、LinkedList类——灵活的双端链表2.1 LinkedList类简介2.2 常用方法2.3 优缺点分析 三、ArrayDeque类——高…...

6.计算机网络核心知识点精要手册

计算机网络核心知识点精要手册 1.协议基础篇 网络协议三要素 语法:数据与控制信息的结构或格式,如同语言中的语法规则语义:控制信息的具体含义和响应方式,规定通信双方"说什么"同步:事件执行的顺序与时序…...

基于Uniapp的HarmonyOS 5.0体育应用开发攻略

一、技术架构设计 1.混合开发框架选型 (1)使用Uniapp 3.8版本支持ArkTS编译 (2)通过uni-harmony插件调用原生能力 (3)分层架构设计: graph TDA[UI层] -->|Vue语法| B(Uniapp框架)B --&g…...

【笔记】AI Agent 项目 SUNA 部署 之 Docker 构建记录

#工作记录 构建过程记录 Microsoft Windows [Version 10.0.27871.1000] (c) Microsoft Corporation. All rights reserved.(suna-py3.12) F:\PythonProjects\suna>python setup.py --admin███████╗██╗ ██╗███╗ ██╗ █████╗ ██╔════╝…...

五、jmeter脚本参数化

目录 1、脚本参数化 1.1 用户定义的变量 1.1.1 添加及引用方式 1.1.2 测试得出用户定义变量的特点 1.2 用户参数 1.2.1 概念 1.2.2 位置不同效果不同 1.2.3、用户参数的勾选框 - 每次迭代更新一次 总结用户定义的变量、用户参数 1.3 csv数据文件参数化 1、脚本参数化 …...

python基础语法Ⅰ

python基础语法Ⅰ 常量和表达式变量是什么变量的语法1.定义变量使用变量 变量的类型1.整数2.浮点数(小数)3.字符串4.布尔5.其他 动态类型特征注释注释是什么注释的语法1.行注释2.文档字符串 注释的规范 常量和表达式 我们可以把python当作一个计算器,来进行一些算术…...

C++11 constexpr和字面类型:从入门到精通

文章目录 引言一、constexpr的基本概念与使用1.1 constexpr的定义与作用1.2 constexpr变量1.3 constexpr函数1.4 constexpr在类构造函数中的应用1.5 constexpr的优势 二、字面类型的基本概念与使用2.1 字面类型的定义与作用2.2 字面类型的应用场景2.2.1 常量定义2.2.2 模板参数…...

EEG-fNIRS联合成像在跨频率耦合研究中的创新应用

摘要 神经影像技术对医学科学产生了深远的影响,推动了许多神经系统疾病研究的进展并改善了其诊断方法。在此背景下,基于神经血管耦合现象的多模态神经影像方法,通过融合各自优势来提供有关大脑皮层神经活动的互补信息。在这里,本研…...

python打卡day49@浙大疏锦行

知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 一、通道注意力模块复习 & CBAM实现 import torch import torch.nn as nnclass CBAM(nn.Module):def __init__…...

Qt Quick Controls模块功能及架构

Qt Quick Controls是Qt Quick的一个附加模块,提供了一套用于构建完整用户界面的UI控件。在Qt 6.0中,这个模块经历了重大重构和改进。 一、主要功能和特点 1. 架构重构 完全重写了底层架构,与Qt Quick更紧密集成 移除了对Qt Widgets的依赖&…...

手动给中文分词和 直接用神经网络RNN做有什么区别

手动分词和基于神经网络(如 RNN)的自动分词在原理、实现方式和效果上有显著差异,以下是核心对比: 1. 实现原理对比 对比维度手动分词(规则 / 词典驱动)神经网络 RNN 分词(数据驱动&#xff09…...

C++中vector类型的介绍和使用

文章目录 一、vector 类型的简介1.1 基本介绍1.2 常见用法示例1.3 常见成员函数简表 二、vector 数据的插入2.1 push_back() —— 在尾部插入一个元素2.2 emplace_back() —— 在尾部“就地”构造对象2.3 insert() —— 在任意位置插入一个或多个元素2.4 emplace() —— 在任意…...

计算机系统结构复习-名词解释2

1.定向:在某条指令产生计算结果之前,其他指令并不真正立即需要该计算结果,如果能够将该计算结果从其产生的地方直接送到其他指令中需要它的地方,那么就可以避免停顿。 2.多级存储层次:由若干个采用不同实现技术的存储…...

HTML中各种标签的作用

一、HTML文件主要标签结构及说明 1. <&#xff01;DOCTYPE html> 作用&#xff1a;声明文档类型&#xff0c;告知浏览器这是 HTML5 文档。 必须&#xff1a;是。 2. <html lang“zh”>. </html> 作用&#xff1a;包裹整个网页内容&#xff0c;lang"z…...

CVE-2023-25194源码分析与漏洞复现(Kafka JNDI注入)

漏洞概述 漏洞名称&#xff1a;Apache Kafka Connect JNDI注入导致的远程代码执行漏洞 CVE编号&#xff1a;CVE-2023-25194 CVSS评分&#xff1a;8.8 影响版本&#xff1a;Apache Kafka 2.3.0 - 3.3.2 修复版本&#xff1a;≥ 3.4.0 漏洞类型&#xff1a;反序列化导致的远程代…...

统计学(第8版)——统计抽样学习笔记(考试用)

一、统计抽样的核心内容与问题 研究内容 从总体中科学抽取样本的方法利用样本数据推断总体特征&#xff08;均值、比率、总量&#xff09;控制抽样误差与非抽样误差 解决的核心问题 在成本约束下&#xff0c;用少量样本准确推断总体特征量化估计结果的可靠性&#xff08;置…...

Copilot for Xcode (iOS的 AI辅助编程)

Copilot for Xcode 简介Copilot下载与安装 体验环境要求下载最新的安装包安装登录系统权限设置 AI辅助编程生成注释代码补全简单需求代码生成辅助编程行间代码生成注释联想 代码生成 总结 简介 尝试使用了Copilot&#xff0c;它能根据上下文补全代码&#xff0c;快速生成常用…...