抽象工厂模式(Abstract Factory Pattern)详解


一、抽象工厂模式简介

抽象工厂模式(Abstract Factory Pattern) 是一种 创建型设计模式(对象创建型模式),它提供了一种创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
抽象工厂模式的核心在于“抽象”,通过定义一个创建对象的接口,但由子类决定要实例化的类是哪一个。

你可以这样理解:

“抽象工厂就像是一个‘品牌制造商’,根据不同的需求生产出不同品牌的同类产品(如手机、电脑),每个品牌的产品都是相关的,但具体实现各有特色。”

工厂方法模式
每个具体工厂只有一个或者一组重载的工厂方法,只能生产一种产品,可能会导致系统中存在大量的工厂类,势必会增加系统的开销
抽象工厂模式
一个工厂可以生产一系列产品(一族产品),极大减少了工厂类的数量

产品等级结构:产品等级结构即产品的继承结构
产品族:产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品

在这里插入图片描述
当系统所提供的工厂生产的具体产品并不是一个简单的对象,而是多个位于不同产品等级结构、属于不同类型的具体产品时就可以使用抽象工厂模式。
抽象工厂模式是所有形式的工厂模式中最为抽象和最具一般性的一种形式。

又称为工具(Kit)模式
抽象工厂模式中的具体工厂不只是创建一种产品,它负责创建一族产品
当一个工厂等级结构可以创建出分属于不同产品等级结构的一个产品族中的所有对象时,抽象工厂模式比工厂方法模式更为简单、更有效率。

抽象工厂模式包含以下4个角色
AbstractFactory(抽象工厂)
ConcreteFactory(具体工厂)
AbstractProduct(抽象产品)
ConcreteProduct(具体产品)

在这里插入图片描述


二、解决的问题类型

抽象工厂模式主要用于解决以下问题:

  • 需要创建一系列相关对象:这些对象通常是一起使用的,例如一套图形界面组件(按钮、文本框等)。
  • 希望隐藏具体产品的创建逻辑:避免客户端直接使用 new 关键字来实例化具体类。
  • 支持扩展性:新增产品族时只需添加新的具体工厂和产品实现,无需修改已有代码。

三、使用场景

场景示例
UI 组件库如 Windows 和 Mac 系统下的按钮、窗口等组件
数据库连接池提供多种数据库的连接管理(MySQL, PostgreSQL 等)
游戏中的角色装备系统不同等级的角色拥有不同级别的武器和防具

一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节。
系统中有多于一个的产品族,但每次只使用其中某一产品族。
属于同一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来。
产品等级结构稳定,设计完成之后,不会向系统中增加新的产品等级结构或者删除已有的产品等级结构。


四、核心概念

  1. AbstractFactory(抽象工厂):声明一组用于创建抽象产品的方法。
  2. ConcreteFactory(具体工厂):实现抽象工厂中定义的方法,负责创建具体产品对象。
  3. AbstractProduct(抽象产品):为每类产品定义接口或基类。
  4. ConcreteProduct(具体产品):实现抽象产品接口的具体类。

五、实际代码案例(Java)

我们以“跨平台UI组件”为例,演示抽象工厂模式的应用。假设我们需要在Windows和MacOS平台上显示按钮和文本框。

1. 定义抽象产品接口

// 按钮接口
public interface Button {void paint();
}// 文本框接口
public interface TextBox {void displayText(String text);
}

2. 创建具体产品类

// Windows风格按钮
public class WindowsButton implements Button {@Overridepublic void paint() {System.out.println("绘制 Windows 样式的按钮");}
}// MacOS风格按钮
public class MacOSButton implements Button {@Overridepublic void paint() {System.out.println("绘制 MacOS 样式的按钮");}
}// Windows风格文本框
public class WindowsTextBox implements TextBox {@Overridepublic void displayText(String text) {System.out.println("在 Windows 样式的文本框中显示: " + text);}
}// MacOS风格文本框
public class MacOSTextBox implements TextBox {@Overridepublic void displayText(String text) {System.out.println("在 MacOS 样式的文本框中显示: " + text);}
}

3. 定义抽象工厂接口

// GUI工厂接口
public interface GUIFactory {Button createButton();TextBox createTextBox();
}

4. 创建具体工厂类

// Windows风格GUI工厂
public class WindowsFactory implements GUIFactory {@Overridepublic Button createButton() {return new WindowsButton();}@Overridepublic TextBox createTextBox() {return new WindowsTextBox();}
}// MacOS风格GUI工厂
public class MacOSFactory implements GUIFactory {@Overridepublic Button createButton() {return new MacOSButton();}@Overridepublic TextBox createTextBox() {return new MacOSTextBox();}
}

5. 客户端测试类

public class Client {private Button button;private TextBox textBox;public Client(GUIFactory factory) {button = factory.createButton();textBox = factory.createTextBox();}public void render() {button.paint();textBox.displayText("Hello World!");}public static void main(String[] args) {String platform = "Windows"; // 假设当前平台为WindowsGUIFactory factory;if (platform.equals("Windows")) {factory = new WindowsFactory();} else {factory = new MacOSFactory();}Client app = new Client(factory);app.render();}
}

输出结果(假设平台为Windows):

绘制 Windows 样式的按钮
在 Windows 样式的文本框中显示: Hello World!

典型代码

典型的抽象工厂类代码:

abstract class AbstractFactory
{
public abstract AbstractProductA CreateProductA(); //工厂方法一
public abstract AbstractProductB CreateProductB(); //工厂方法二
……
}

典型的具体工厂类代码:

class ConcreteFactory1 : AbstractFactory
{//工厂方法一
public override AbstractProductA CreateProductA() 
{return new ConcreteProductA1();
}
//工厂方法二
public override AbstractProductB CreateProductB() 
{return new ConcreteProductB1();
}
……
}

其他案例

  1. 某软件公司要开发一套界面皮肤库,可以对基于.NET平台的桌面软件进行界面美化。用户在使用时可以通过菜单来选择皮肤,不同的皮肤将提供视觉效果不同的按钮、文本框、组合框等界面元素,例如春天(Spring)风格的皮肤将提供浅绿色的按钮、绿色边框的文本框和绿色边框的组合框,而夏天(Summer)风格的皮肤则提供浅蓝色的按钮、蓝色边框的文本框和蓝色边框的组合框,其结构示意图如下图所示:
    在这里插入图片描述
    该皮肤库需要具备良好的灵活性和可扩展性,用户可以自由选择不同的皮肤,开发人员可以在不修改既有代码的基础上增加新的皮肤。
    现使用抽象工厂模式来设计该界面皮肤库。

在这里插入图片描述

  1. 电器工厂
    一个电器工厂可以产生多种类型的电器,如海尔工厂可以生产海尔电视机、海尔空调等,TCL工厂可以生产TCL电视机、TCL空调等,相同品牌的电器构成一个产品族,而相同类型的电器构成了一个产品等级结构,现使用抽象工厂模式模拟该场景

在这里插入图片描述

  1. 数据库操作工厂
    某系统为了改进数据库操作的性能,自定义数据库连接对象Connection和语句对象Statement,可针对不同类型的数据库提供不同的连接对象和语句对象,如提供Oracle或SQL Server专用连接类和语句类,而且用户可以通过配置文件等方式根据实际需要动态更换系统数据库。使用抽象工厂模式设计该系统。

在这里插入图片描述


六、优缺点分析

优点描述
统一接口通过抽象层隔离了具体产品的创建过程,使得客户端仅需知道抽象接口即可
易于扩展新增产品族时只需添加新的具体工厂和产品实现,不影响现有代码
增强灵活性可以轻松切换到不同的产品族
缺点描述
增加复杂度引入了额外的抽象层次,可能使系统更加复杂。增加新的产品等级结构麻烦,需要对原有系统进行较大的修改,甚至需要修改抽象层代码,这显然会带来较大的不便,违背了开闭原则
不便于单独替换产品更换某一具体产品时可能需要修改所有相关工厂类

七、与其他模式对比(补充)

模式名称目标
简单工厂模式通过静态方法集中创建对象,适用于单一产品族的情况
工厂方法模式提供一个创建对象的接口,但由子类决定实例化哪一个类
抽象工厂模式创建一系列相关或相互依赖的对象,适合多个产品族的场景

八、最终小结

抽象工厂模式是一种强大的创建型设计模式,特别适用于那些需要创建一系列相关对象且希望保持高度灵活性和可扩展性的场景。通过将对象的创建逻辑封装在抽象工厂中,我们可以有效地分离关注点,提高系统的模块化程度。

在开发跨平台应用、多数据库支持系统、游戏引擎等项目中,抽象工厂模式能够帮助你更好地组织代码结构,减少重复代码,并提高系统的可维护性和可扩展性。


📌 一句话总结:

抽象工厂模式就像一个“产品生产线”,可以根据不同的需求生产出一系列配套的产品,确保产品之间的一致性和兼容性。


推荐使用场景:

  • 当你需要创建一组相关的对象时;
  • 希望将对象创建的逻辑集中在一处进行管理;
  • 需要在运行时动态选择产品族。

扩展

开闭原则的倾斜性

增加产品族
对于增加新的产品族,抽象工厂模式很好地支持了开闭原则,只需要增加具体产品并对应增加一个新的具体工厂,对已有代码无须做任何修改
增加新的产品等级结构
对于增加新的产品等级结构,需要修改所有的工厂角色,包括抽象工厂类,在所有的工厂类中都需要增加生产新产品的方法,违背了开闭原则

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

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

相关文章

Android初学者系统开发学习路线参考

Android初学者系统开发学习路线参考 文章目录Android初学者系统开发学习路线参考一、前言二、Android初学的学习计划第一阶段(一个月)UI相关学习:开发环境与 UI 基础,第一周:UI 控件与布局进阶,第二周&…

扩散LLM推理新范式:打破生成长度限制,实现动态自适应调节

随着 Gemini-Diffusion,Seed-Diffusion 等扩散大语言模型(DLLM)的发布,这一领域成为了工业界和学术界的热门方向。但是,当前 DLLM 存在着在推理时必须采用预设固定长度的限制,对于不同任务都需要专门调整才…

【ee类保研面试】其他类---计算机网络

25保研er,希望将自己的面试复习分享出来,供大家参考 part0—英语类 part1—通信类 part2—信号类 part3—高数类 part100—self项目准备 文章目录计算机网络知识点大全**计算机网络知识点总结**一、五层协议模型二、OSI七层模型补充三、TCP 与 UDP 及区别…

Python-机器学习(一)——特征工程

目录 特征工程 一、特征提取 1、字典特征提取 2、文本特征提取 2.1 英文文本提取 2.2 中文文本提取 3、TF-IDF文本特征词的重要程度特征提取 二、无量纲化-预处理 1 MinMaxScaler 归一化 2 normalize归一化 3 StandardScaler 标准化 三、特征降维 1、特征选择 1.…

谈谈SQL计算存储引擎中的索引和计算

背景 最近在这家公司做了一些事情,做的事情和以往的工作不太一样,不一样的点呢就是 之前我主要的工作是关注计算这方面,因为数据量大,研究的是怎么加速查询,怎么研究规则去优化,怎么去解规则的bug等等。因为…

vscode.window.activeTextEditor 获取不到 png 图片路径问题

vscode 的 extensions 插件开发时用 vscode.window.activeTextEditor?.document.uri 获取不到编辑器打开的图片路径,文档路径可以获取到。个人猜测因为图片不能编辑,所以没有 activeTextEditor 属性吧。解决办法:巧用右键获取路径和相对的路…

Java 大视界 -- Java 大数据在智能医疗手术机器人操作数据记录与性能评估中的应用(390)

Java 大视界 -- Java 大数据在智能医疗手术机器人操作数据记录与性能评估中的应用(390)引言:正文:一、传统手术机器人的 “黑箱困境”:记不全、算不清、追不到1.1 设备与临床的 “断层”1.1.1 数据记录 “太粗放”1.1.…

C++的结构体指针

结构体变量和结构体指针的区别特性结构体变量结构体指针存储内容结构体的实际数据内存地址内存开销结构体总大小固定4/8字节(指针大小)成员访问运算符.->函数传参时的行为值拷贝(新副本)地址传递(操作原数据&#x…

pdf文件转word免费使用几个工具

在线工具(无需安装) Smallpdf ✅ 核心功能: 网页端直接操作,支持 PDF 与 Word 格式互转 免费用户每日限 2 次转换(免注册) 自动清除服务器文件,确保隐私安全 🔗 访问链接&#xff1a…

Vue3 组件化开发

文章目录前言组件化开发底部菜单 TabMenu父子组件相互传数据父传子:自定义属性子传父:自定义事件父子组件互传案例插槽 slot多个插槽总结组件化开发总结Vue组件的基本组成子组件使用的三个步骤父子组件相互传递数据前言 提示:这里可以添加本…

服务器硬件电路设计之I2C问答(二):I2C总线的传输速率与上拉电阻有什么关系?

I2C 总线传输速率与上拉电阻关系密切。上拉电阻阻值决定总线电平切换速度:电阻越小,充放电电流越大,信号边沿更陡,支持更高速率(如 400kHz 快速模式);电阻过大则切换慢,限制速率&…

大语言模型提示工程与应用:LLMs文本生成与数据标注实践

提示词应用实践 学习目标 本课程通过LLMs生成情感分析样本和标注葡萄9品鉴数据,展示了其文本生成和数据标注能力。同时,利用PAL模型解决日期计算问题,学习了LLMs与编程运行时结合实现复杂推理的方法,为自然语言处理应用提供了实…

node.js 零基础入门

Node.js 零 基础入门与核心语法 适用对象:完全没接触过 Node.js 的同学 目标:从 0 到能写 CLI、小型 HTTP 服务、文件脚本、调用系统/网络资源 目录 什么是 Node.js安装与运行运行脚本与 REPL模块体系:CommonJS 与 ES Modules基础语法在 Node…

《Day3-PyTorch 自动微分入门:从计算图到梯度下降的实践指南》

八、自动微分自动微分模块torch.autograd负责自动计算张量操作的梯度,具有自动求导功能。自动微分模块是构成神经网络训练的必要模块,可以实现网络权重参数的更新,使得反向传播算法的实现变得简单而高效。1. 基础概念张量Torch中一切皆为张量…

apache cgi测试

test.cgi #!/bin/sh echo "Content-type: text/html" echo "" echo "<h1>Hello from a Mac CGI script!</h1>" echo "<p>Current time is: $(date)</p>"ƒ% 放置目录 /opt/homebrew/Cellar/mapserver/8.4.0_1…

力扣 30 天 JavaScript 挑战 第二题笔记

这道题是涉及知识–闭包 1. 闭包定义以及相关知识点 官方定义为&#xff1a;在 JavaScript 中&#xff0c;函数具有对在相同作用域以及任何外部作用域中声明的所有变量的引用。这些作用域被称为函数的 词法环境。函数与其环境的组合被称为 闭包。 简单理解&#xff1a;内层函数…

OpenAI GPT-5 深度解析:API Key定价与ChatGPT(Free, Plus, Pro)用户的区别

前言&#xff1a;两年等待&#xff0c;只为这一跃 在科技圈长达两年的屏息期待与无尽猜想之后&#xff0c;2025年8月8日北京时间凌晨&#xff0c;OpenAI终于揭开了其新一代旗舰模型——GPT-5的神秘面纱。这不仅仅是一次常规的产品迭代&#xff0c;更被整个行业视为一块试金石&a…

ClickHouse集群部署实践---3分片2副本集群

ClickHouse集群部署实践—3分片2副本集群 未完待续。。。 喜欢的先点赞收藏&#xff01;&#xff01; 由于我们准备部署的是3分片2副本的集群&#xff0c;现在来解释一下配置参数的意思&#xff1a; shard标签代表分片的意思&#xff0c;如上图我们有3个分片&#xff0c;clickh…

Unity_VR_Pico开发手册

文章目录一、配置开发环境1.下载PICO Unity Integration SDK2.安装 Unity 编辑器&#xff08;添加安卓开发平台模块&#xff09;3.导入下载的SDK4.项目配置和切换开发平台5.导入 XR Interaction Toolkit6.安装 Universal RP(通用渲染管线)并设置 (选做)二、调试环境搭建&#x…

Linux系统之Docker命令与镜像、容器管理

目录 一、 Docker命令 docker命令帮助 docker常用子命令&#xff08;必须背会&#xff09; docker管理子命令(暂时不需要) swarm集群管理子命令&#xff08;不需要&#xff09; docker容器管理子命令&#xff08;必须背会&#xff09; docker全局选项 二、 docker镜像管…