23种设计模式——抽象工厂模式(Abstract Factory Pattern)详解

✅作者简介:大家好,我是 Meteors., 向往着更加简洁高效的代码写法与编程方式,持续分享Java技术内容。
🍎个人主页:Meteors.的博客
💞当前专栏:设计模式
✨特色专栏:知识分享
🥭本文内容:23种设计模式——抽象工厂模式(Abstract Factory Pattern)
📚 ** ps **  :阅读文章如果有问题或者疑惑,欢迎在评论区提问或指出。


目录

一. 背景

二. 介绍

三. 核心角色

四. 代码示例

1.​​抽象产品 & 具体产品​

2. 抽象工厂 & 具体工厂​

3. 客户端代码​

五.  与简单工厂、工厂方法的区别

六. 抽象工厂模式的优缺点

七. 总结与应用场景


一. 背景

对于工厂方法模式,会有一个工厂类里面有一个抽象工厂方法并且返回类型是一个接口基类(大白话讲就是这个方法创建了一个基类的不同实现类,如基类为按钮,我们就可以通过这个方法创建圆形按钮或者方形按钮);

但如果现在有个界面,不仅仅要创建不同类型的按钮,还要创建不同类型的文本框、字体......这种情况怎么办?其实这个时候我们就可以创建一个抽象工厂模式(就是这个界面),里面有多个抽象工厂方法(创建按钮的、创建文本框的、创建字体的......)。抽象工厂。它本质上是​​多个工厂方法的组合,这些方法共同生产一个产品族。


二. 介绍

抽象工厂模式​​是一种创建型设计模式,它提供一个接口,用于创建​​相关或依赖对象​​的​​家族​​,而不需要明确指定具体类。

你可以将其理解为“工厂的工厂”。客户端代码不直接通过new来实例化具体的产品,而是通过一个抽象的接口来创建一整组相关的产品。这使得客户端代码与具体的产品类解耦,并且能确保所创建的产品是相互兼容的。


三. 核心角色

  1. ​抽象工厂​​:声明一个创建​​一族产品​​(多个不同产品等级)的接口,包含多个创建产品的方法,如 createButton()createTextBox()
  2. ​具体工厂​​:实现抽象工厂的接口,负责创建某一族具体的产品。例如,WindowsFactory 创建 Windows 风格的按钮和文本框,MacFactory 创建 Mac 风格的按钮和文本框。
  3. ​抽象产品​​:声明每种产品类型的接口。例如,Button 和 TextBox
  4. ​具体产品​​:实现抽象产品接口,由具体工厂创建。例如,WindowsButtonMacButtonWindowsTextBoxMacTextBox

四. 代码示例

用一个界面为例:

1.​​抽象产品 & 具体产品​

// 抽象产品:按钮
public interface Button {void render();void onClick();
}// 具体产品:Windows按钮
public class WindowsButton implements Button {@Overridepublic void render() {System.out.println("渲染一个Windows风格的按钮");}@Overridepublic void onClick() {System.out.println("Windows按钮被点击!");}
}// 具体产品:Mac按钮
public class MacButton implements Button {@Overridepublic void render() {System.out.println("渲染一个Mac风格的按钮");}@Overridepublic void onClick() {System.out.println("Mac按钮被点击!");}
}// 抽象产品:文本框
public interface TextBox {void render();
}// 具体产品:Windows文本框
public class WindowsTextBox implements TextBox {@Overridepublic void render() {System.out.println("渲染一个Windows风格的文本框");}
}// 具体产品:Mac文本框
public class MacTextBox implements TextBox {@Overridepublic void render() {System.out.println("渲染一个Mac风格的文本框");}
}

2. 抽象工厂 & 具体工厂​

// 抽象工厂
public interface GUIFactory {Button createButton();TextBox createTextBox();
}// 具体工厂:Windows工厂
public class WindowsFactory implements GUIFactory {@Overridepublic Button createButton() {return new WindowsButton();}@Overridepublic TextBox createTextBox() {return new WindowsTextBox();}
}// 具体工厂:Mac工厂
public class MacFactory implements GUIFactory {@Overridepublic Button createButton() {return new MacButton();}@Overridepublic TextBox createTextBox() {return new MacTextBox();}
}

3. 客户端代码​

客户端代码只依赖抽象工厂和抽象产品,从而与具体平台解耦。

public class Application {private Button button;private TextBox textBox;// 通过构造器注入一个具体的工厂public Application(GUIFactory factory) {button = factory.createButton();textBox = factory.createTextBox();}public void renderUI() {button.render();textBox.render();}public static void main(String[] args) {// 根据配置或环境决定使用哪种工厂GUIFactory factory;String osName = System.getProperty("os.name").toLowerCase();if (osName.contains("win")) {factory = new WindowsFactory();} else {factory = new MacFactory();}Application app = new Application(factory);app.renderUI();// 输出:// 如果是Windows: //   渲染一个Windows风格的按钮//   渲染一个Windows风格的文本框// 如果是Mac://   渲染一个Mac风格的按钮//   渲染一个Mac风格的文本框}
}

五.  与简单工厂、工厂方法的区别

特征简单工厂工厂方法抽象工厂
​核心思想​由一个工厂类根据传入的参数,​​静态​​地决定创建哪一种产品。定义一个创建对象的接口,但让​​子类​​决定实例化哪一个类。提供一个接口,用于创建​​相关或依赖对象​​的​​家族​​,而不指定具体类。
​工厂角色​一个​​具体工厂​​类,包含创建所有产品的逻辑。一个​​抽象工厂​​接口和多个​​具体工厂​​实现(每个对应一个产品)。一个​​抽象工厂​​接口和多个​​具体工厂​​实现(每个对应一族产品)。
​产品维度​​一个产品等级​​(例如:只有按钮)。​一个产品等级​​(例如:只有按钮)。​多个产品等级​​(例如:按钮、文本框、复选框等​​一套产品​​)。
​扩展性​​违反开闭原则​​。要新增产品,必须修改工厂类的逻辑。​符合开闭原则​​。要新增产品,只需新增一个具体工厂即可。​符合开闭原则​​。但要新增一个产品族(如Linux主题)很容易,​​新增一个产品等级​​(如新增Slider滑块)很困难,需要修改所有工厂接口和类。
​复杂度/适用场景​简单,适用于产品类型较少且几乎不会变化的场景。适中,适用于产品结构单一但需要灵活扩展的场景。复杂,适用于需要创建一整系列相互关联、相互依赖的产品,并保证它们兼容的场景。

演进关系(从简单到复杂):

  1. .简单工厂​​:如果你只有一个产品(比如只有Button),用简单工厂就够了。
  2. 工厂方法​​:当你的产品变得复杂,或者你希望扩展时不修改原有代码(比如未来要加LinuxButton),你就为每种按钮建立一个专门的工厂。
  3. 抽象工厂​​:当你不止有按钮,还有文本框、复选框等​​一整套需要搭配使用​​的产品时,工厂方法就不够了。你需要一个能创建​​整套产品​​的工厂,这就是抽象工厂。它本质上是​​多个工厂方法的组合​​,这些方法共同生产一个产品族。

六. 抽象工厂模式的优缺点

​优点:​

  • 保证了产品的兼容性​​:确保客户端始终只使用同一产品族中的对象。你不会把一个Windows按钮和一个Mac文本框混在一起用。
  • 解耦客户端与具体产品​​:客户端代码只面向抽象接口编程,使得切换整个产品族变得非常容易(只需换一个具体工厂)。
  • 符合开闭原则​​:易于扩展新的产品族(如新增一个LinuxFactory)。

​缺点:​

  • 难以支持新的产品种类​​:这是最大的缺点。如果要为所有工厂增加一个新的产品(如在产品族中增加Slider滑块),就需要修改抽象工厂接口GUIFactory,这会导致所有具体工厂类(WindowsFactoryMacFactory)都需要被修改,违反了开闭原则。
  • 增加了系统的复杂性​​:类会变得非常多(n个产品族 * m个产品等级 = n*m个类)。

七. 总结与应用场景

​抽象工厂模式的核心是创建产品族。​

​典型应用场景:​

  • 系统需要独立于其产品的创建、组合和表示时​​。
  • ​系统需要配置多个产品族中的某一个时​​。
  • 需要强调一系列相关产品对象的设计以便进行联合使用时​​。
  • 希望提供一个产品类库,但只想暴露它们的接口而不是实现时​​。

​经典例子:​

  • ​跨平台GUI开发​​(如Java AWT/Swing, QT)。
  • 数据库访问层​​:ConnectionCommandDataAdapter 构成一个产品族,可以轻松在 SqlServerFactory 和 OracleFactory 之间切换。
  • 游戏开发​​:为不同风格(科幻、中世纪)的场景创建一套主题资源(建筑、士兵、植被)。
  • ​日志记录器​​:创建一套相关的日志组件(记录器、格式化器、附加器)。

最后,

        其它设计模式会陆续更新,希望文章对你有所帮助!

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

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

相关文章

本地部署开源数据生成器项目实战指南

本地部署开源数据生成器项目实战指南 前言 在当今大数据和人工智能时代,高质量数据集对于模型训练和算法开发至关重要。然而,获取真实且合规的数据集往往面临隐私、成本和法律等多重挑战。合成数据生成技术为此提供了优雅的解决方案,它能够…

2025React面试题集锦

1. React 是什么?它有哪些主要特点? React 是由Facebook开发的开源JavaScript库,用于构建用户界面(UI),尤其适合开发复杂的单页应用(SPA)。 主要特点: 声明式编程:只需描述UI应该是什么样子(如return <div>Hello</div>),React会自动处理DOM更新,无需…

设计模式:迭代器模式(Iterator Pattern)

文章目录一、概念二、实例分析三、示例代码一、概念 迭代器模式 是一种 行为型设计模式&#xff0c;用于在不暴露集合对象内部结构的前提下&#xff0c;顺序访问集合中的元素。 换句话说&#xff1a; 集合类只负责数据存储&#xff1b;迭代器类负责遍历集合&#xff1b;使用者…

Vue 3 学习路线指南

阶段一:基础入门 (1-2周) 1.1 环境准备 # 安装 Node.js (推荐 18+ 版本) # 安装 Vue CLI 或使用 Vite npm create vue@latest my-vue-app cd my-vue-app npm install npm run dev1.2 Vue 3 核心概念 响应式系统:ref(), reactive(), computed() 组合式 API:setup() 函数 模…

使用 `hover:not-[:has(:hover)]` 避免「父元素和子元素同时 hover」时的样式冲突

:hover:not-(:has(:hover)) has() CSS 4 引入的“父选择器”&#xff0c;意思是&#xff1a;匹配那些里面包含某个子元素/状态的元素。 例如&#xff1a;:has(:hover) 表示「自身包含正在被 hover 的子元素」。 :not() 取反伪类&#xff0c;表示不匹配里面的条件。 比如我…

第三十天-DMA串口实验

一、DMA概述二、DMA通道注意&#xff0c;想要往串口中写数据&#xff0c;外部请求信号应该是USARTx_TX&#xff0c;当DR寄存器为空时&#xff0c;产生TX信号&#xff0c;请求DMA。反之&#xff0c;从串口中读数据&#xff0c;外部请求信号应该是USARTx_RX&#xff0c;当DR寄存器…

C/C++ 中的inline(内联函数关键字)详解

在 C/C 编程中&#xff0c;函数调用虽然带来了代码复用和可读性提升&#xff0c;但频繁调用小型函数可能会产生额外的调用开销&#xff08;call overhead&#xff09;&#xff0c;比如栈帧的建立与销毁、参数传递等。 为了减少这种开销&#xff0c;C 引入了 inline&#xff08;…

2025 年高教社杯全国大学生数学建模竞赛A 题 烟幕干扰弹的投放策略完整成品 思路 模型 代码 结果 全网首发高质量!!!

烟幕干扰弹主要通过化学燃烧或爆炸分散形成烟幕或气溶胶云团,在目标前方特定空域形成遮蔽&#xff0c;干扰敌方导弹&#xff0c;具有成本低、效费比高等优点。随着烟幕干扰技术的不断发展&#xff0c;现已有多种投放方式完成烟幕干扰弹的定点精确抛撒,即在抛撒前能精确控制烟幕…

嵌入式第四十五天(51单片机相关)

一.1.CPU、MPU、MCU、GPU&#xff1a; CPU&#xff08;中央处理器&#xff09;&#xff1a;计算机的核心部件&#xff0c;负责执行指令和处理数据。 MPU&#xff08;微处理器&#xff09;&#xff1a;通常指更通用的处理器&#xff0c;强调计算能力。 MCU&#xff08;微控制器&…

今天面了一个Java后端工程师,真的让我猛抬头

今天面了一个Java后端工程师,真的让我猛抬头啊. 现在面试不像传统的八股文面试,我更多问的都是项目场景相关的问题,但是都能回答的不错.这一点我还是很惊讶的。 不仅如此,她的技术也很扎实,对Java核心机制&#xff08;JVM、并发、集合等&#xff09;理解深入&#xff0c;回答…

拦截器和过滤器(理论+实操)

拦截器和过滤器 本文旨在夯实基础以及实战加深理解,目的是更深的理解以便掌握,希望能跟着动手敲一遍,绝对受益匪浅 在本文,我会先给出两者的区别(理论知识),随后是两者各自的实操实现 文章目录拦截器和过滤器什么是过滤器和拦截器?1.过滤器2.拦截器执行整体流程拦截器和过滤器…

HTB 赛季8靶场 - Guardian

各位好&#xff0c;最近我的kali崩掉了&#xff0c;崩掉了&#xff0c;建议大家避K 番茄C盘瘦身&#xff0c;这家伙修改了我的avrt.dll文件&#xff0c;导致virtualbox不接受我的avrt.dll文件的签名了&#xff0c;从而导致virtualbox的虚拟机环境全崩无法开机。弄了几天&#x…

Rust+slint实现一个登录demo

系列文章目录 文章目录系列文章目录前言一、为什么前端选择slint而不是Tauri或者其他GUI框架二、开发工具三、代码编写项目结构前端代码编写后端开发编写运行效果总结前言 本文章就是一个简单rust全栈编程的一个小小的示例供rust新手阅读学习。 一、为什么前端选择slint而不是…

2025前端面试题及答案(详细)

HTML5 的新特性有哪些&#xff1f;简约版本&#xff1a;“HTML5 新特性主要体现在六个方面&#xff1a; 第一&#xff0c;语义化标签&#xff0c;比如 header、footer、nav 等&#xff0c;让页面结构更清晰&#xff1b; 第二&#xff0c;表单增强&#xff0c;新增了 date、emai…

分词器详解(二)

&#x1f50d; 第2层&#xff1a;中等深度&#xff08;15分钟理解&#xff09; 1. 理论基础 1.1 BPE的数学原理 核心思想&#xff1a;通过迭代合并高频字符对构建词汇表 算法形式化&#xff1a; 初始化词汇表 V0{c1,c2,...,cn}V_0 \{c_1, c_2, ..., c_n\}V0​{c1​,c2​,...,c…

嵌入式学习 51单片机(3)

UART 概述通用异步收发器&#xff08;UART&#xff09;是一种全双工、串行、异步通信协议&#xff0c;常用于设备间数据传输。包含两根信号线&#xff1a;RXD&#xff08;接收信号线&#xff09;TXD&#xff08;发送信号线&#xff09;通信方式单工通信方向固定&#xff0c;仅支…

Redis AOF 持久化:银行的 “交易流水单” 管理逻辑

目录 一、AOF 的核心逻辑&#xff1a;“每笔交易都记流水” 二、AOF 的三个步骤&#xff1a;从 “临时记录” 到 “正式归档” 1. 命令追加&#xff1a;记到 “临时小本本” 2. 写入与同步&#xff1a;抄到 “正式流水册” 3. AOF 还原&#xff1a;拿 “流水册” 重放交易…

代码随想录训练营第三十天|LeetCode452.用最少数量的箭引爆气球、LeetCode435.无重叠空间、LeetCode763.划分字母空间

452.用最少数量的箭引爆气球 贪心算法 重合最多的气球射一箭&#xff0c;就是局部用箭数量最少的&#xff0c;全局的用箭数量就是最少的。 首先对二维数组进行排序&#xff0c;这样就可以让气球更加紧凑。 思路&#xff1a;当前气球是否和上一个气球区间重合&#xff0c;如…

数据库事务隔离级别与 MVCC 机制详解

最近在准备面试&#xff0c;正把平时积累的笔记、项目中遇到的问题与解决方案、对核心原理的理解&#xff0c;以及高频业务场景的应对策略系统梳理一遍&#xff0c;既能加深记忆&#xff0c;也能让知识体系更扎实&#xff0c;供大家参考&#xff0c;欢迎讨论。在数据库并发操作…

【Cursor-Gpt-5-high】StackCube-v1 任务训练结果不稳定性的分析

1. Prompt 我是机器人RL方向的博士生正在学习ManiSkill&#xff0c;在学习时我尝试使用相同命令训练同一个任务&#xff0c;但是我发现最终的 success_once 指标并不是相同的&#xff0c;我感到十分焦虑&#xff0c; 我使用的命令如下&#xff1a; python sac.py --env_id"…