23种设计模式-抽象工厂(Abstract Factory)设计模式
文章目录
- 一.什么是抽象工厂设计模式?
- 二.抽象工厂模式的特点
- 三.抽象工厂模式的结构
- 四.抽象工厂模式的优缺点
- 五.抽象工厂模式的 C++ 实现
- 六.抽象工厂模式的 Java 实现
- 七.代码解析
- 八.总结
类图: 抽象工厂设计模式类图
一.什么是抽象工厂设计模式?
抽象工厂模式(Abstract Factory Pattern) 是一种创建型设计模式,它提供一个接口,用于创建一系列相关或相互依赖的对象,而无需指定它们的具体类。
与工厂方法模式的区别在于,抽象工厂模式更注重产品族的概念,可以同时创建多个相关的产品对象。
二.抽象工厂模式的特点
- 多产品创建:可以创建一组相关联的对象(如按钮和文本框)。
- 解耦性强:客户端只需调用工厂接口创建对象,而不需要关心具体实现。
- 可扩展性:可以通过增加新的工厂子类来扩展产品系列。
三.抽象工厂模式的结构
- AbstractFactory(抽象工厂):声明了一组创建产品的方法。
- ConcreteFactory(具体工厂):实现抽象工厂的接口,创建具体的产品。
- AbstractProduct(抽象产品):定义产品的接口。
- ConcreteProduct(具体产品):实现抽象产品接口的具体类。
- Client(客户端):通过工厂接口与具体产品交互。
四.抽象工厂模式的优缺点
- 优点:
- 易于扩展:增加新的产品族只需增加对应的具体工厂类和产品类。
- 封装性强:客户端与具体产品实现解耦。
- 符合开闭原则:通过扩展具体工厂类来支持新产品。
- 缺点:
- 增加复杂性:每增加一个产品族,都需要新增具体工厂和产品类。
- 不支持单一产品族扩展:如果只想增加单个产品,可能需要修改抽象工厂接口。
五.抽象工厂模式的 C++ 实现
#include <iostream>
#include <memory>
using namespace std;// 抽象产品A
class AbstractProductA {
public:virtual void MethodA() const = 0;virtual ~AbstractProductA() = default;
};// 抽象产品B
class AbstractProductB {
public:virtual void MethodB() const = 0;virtual ~AbstractProductB() = default;
};// 具体产品A1
class ConcreteProductA1 : public AbstractProductA {
public:void MethodA() const override {cout << "ConcreteProductA1::MethodA" << endl;}
};// 具体产品A2
class ConcreteProductA2 : public AbstractProductA {
public:void MethodA() const override {cout << "ConcreteProductA2::MethodA" << endl;}
};// 具体产品B1
class ConcreteProductB1 : public AbstractProductB {
public:void MethodB() const override {cout << "ConcreteProductB1::MethodB" << endl;}
};// 具体产品B2
class ConcreteProductB2 : public AbstractProductB {
public:void MethodB() const override {cout << "ConcreteProductB2::MethodB" << endl;}
};// 抽象工厂
class AbstractFactory {
public:virtual unique_ptr<AbstractProductA> CreateProductA() const = 0;virtual unique_ptr<AbstractProductB> CreateProductB() const = 0;virtual ~AbstractFactory() = default;
};// 具体工厂1
class ConcreteFactory1 : public AbstractFactory {
public:unique_ptr<AbstractProductA> CreateProductA() const override {return make_unique<ConcreteProductA1>();}unique_ptr<AbstractProductB> CreateProductB() const override {return make_unique<ConcreteProductB1>();}
};// 具体工厂2
class ConcreteFactory2 : public AbstractFactory {
public:unique_ptr<AbstractProductA> CreateProductA() const override {return make_unique<ConcreteProductA2>();}unique_ptr<AbstractProductB> CreateProductB() const override {return make_unique<ConcreteProductB2>();}
};// 客户端代码
void ClientCode(const AbstractFactory& factory) {auto productA = factory.CreateProductA();auto productB = factory.CreateProductB();productA->MethodA();productB->MethodB();
}int main() {cout << "Using ConcreteFactory1:" << endl;ConcreteFactory1 factory1;ClientCode(factory1);cout << "Using ConcreteFactory2:" << endl;ConcreteFactory2 factory2;ClientCode(factory2);return 0;
}
六.抽象工厂模式的 Java 实现
// 抽象产品A
interface ProductA {void methodA();
}// 抽象产品B
interface ProductB {void methodB();
}// 具体产品A1
class ConcreteProductA1 implements ProductA {public void methodA() {System.out.println("ConcreteProductA1::methodA");}
}// 具体产品A2
class ConcreteProductA2 implements ProductA {public void methodA() {System.out.println("ConcreteProductA2::methodA");}
}// 具体产品B1
class ConcreteProductB1 implements ProductB {public void methodB() {System.out.println("ConcreteProductB1::methodB");}
}// 具体产品B2
class ConcreteProductB2 implements ProductB {public void methodB() {System.out.println("ConcreteProductB2::methodB");}
}// 抽象工厂
interface AbstractFactory {ProductA createProductA();ProductB createProductB();
}// 具体工厂1
class ConcreteFactory1 implements AbstractFactory {public ProductA createProductA() {return new ConcreteProductA1();}public ProductB createProductB() {return new ConcreteProductB1();}
}// 具体工厂2
class ConcreteFactory2 implements AbstractFactory {public ProductA createProductA() {return new ConcreteProductA2();}public ProductB createProductB() {return new ConcreteProductB2();}
}// 客户端代码
public class AbstractFactoryDemo {public static void main(String[] args) {AbstractFactory factory1 = new ConcreteFactory1();ProductA productA1 = factory1.createProductA();ProductB productB1 = factory1.createProductB();productA1.methodA();productB1.methodB();AbstractFactory factory2 = new ConcreteFactory2();ProductA productA2 = factory2.createProductA();ProductB productB2 = factory2.createProductB();productA2.methodA();productB2.methodB();}
}
七.代码解析
- 抽象产品类:
- AbstractProductA 和 AbstractProductB 是抽象类,定义了各自的接口方法(如 MethodA 和 MethodB)。
- 具体产品类:
- ConcreteProductA1 和 ConcreteProductA2 实现了 AbstractProductA 接口,表示同一产品族中的不同产品。
- ConcreteProductB1 和 ConcreteProductB2 实现了 AbstractProductB 接口。
- 抽象工厂类:
- AbstractFactory 提供了创建产品的方法接口(CreateProductA 和 CreateProductB),由具体工厂实现。
- 具体工厂类:
- ConcreteFactory1 创建产品族 ConcreteProductA1 和 ConcreteProductB1。
- ConcreteFactory2 创建产品族 ConcreteProductA2 和 ConcreteProductB2。
- 客户端代码:
- 客户端通过抽象工厂创建产品,不需要知道具体工厂和产品的实现细节。
- 多态使得客户端代码具有很强的灵活性。
八.总结
抽象工厂模式在需要创建一组相关对象时非常有用,同时也很好地遵循了依赖倒置原则和开闭原则。通过抽象工厂,客户端只需关心工厂接口,而不需要了解具体产品的实现,从而实现了代码的解耦。尽管增加了系统的复杂性,但在复杂系统中,它可以显著提高代码的灵活性和可维护性。
应用场景:
- 需要创建一组相关或相互依赖的对象:如操作系统中的窗口、按钮和文本框。
- 产品族的概念明确:如不同品牌的家电(冰箱和电视)。
- 客户端不需要知道产品的具体实现:如通过配置文件动态加载具体工厂类。
相关文章:

23种设计模式-抽象工厂(Abstract Factory)设计模式
文章目录 一.什么是抽象工厂设计模式?二.抽象工厂模式的特点三.抽象工厂模式的结构四.抽象工厂模式的优缺点五.抽象工厂模式的 C 实现六.抽象工厂模式的 Java 实现七.代码解析八.总结 类图: 抽象工厂设计模式类图 一.什么是抽象工厂设计模式?…...

手机上怎么拍证件照,操作简单且尺寸颜色标准的方法
在数字化时代,手机已成为我们日常生活中不可或缺的一部分。它不仅是通讯工具,更是我们拍摄证件照的便捷利器。然而,目前证件照制作工具鱼龙混杂,很多打着免费名号的拍照软件背后却存在着泄漏用户信息、照片制作不规范导致无法使用…...

IDEA报错: java: JPS incremental annotation processing is disabled 解决
起因 换了个电脑打开了之前某个老项目IDEA启动springcloud其中某个服务直接报错,信息如下 java: JPS incremental annotation processing is disabled. Compilation results on partial recompilation may be inaccurate. Use build process “jps.track.ap.depen…...
OCR实现微信截图改名
pip install paddlepaddle -i https://pypi.tuna.tsinghua.edu.cn/simple/ ──(Sat,Nov30)─┘ pip install shapely -i https://pypi.tuna.tsinghua.edu.cn/simple/ pip install paddleo…...

第一届“吾杯”网络安全技能大赛 Writeup
战队信息 战队名称:在你眼中我是誰,你想我代替誰? 战队排名:13 Misc Sign Hex 转 Str,即可得到flag。 原神启动! 不好评价,stegsolve 秒了: WuCup{7c16e21c-31c2-439e-a814-b…...

再谈Java中的String类型是否相同的判断方法
目录 第一部分 代码展示 画图展示 第二部分 代码展示 画图展示 第一部分 代码展示 画图展示 第二部分 代码展示 画图展示...
<一>51单片机环境
目录 1,51单片机开发语言是C,环境keil 1.1,工程创建 1.2用什么把代码放进单片机里面 2,初识代码 1,51单片机开发语言是C,环境keil 1.1,工程创建 1. 创建项目工程文件夹,可以当作模板Template 2. 创建文件,取名main.c 3,编译,选择输出文…...

【0x0001】HCI_Set_Event_Mask详解
目录 一、命令概述 二、命令格式 三、命令参数说明 四、返回参数说明 五、命令执行流程 5.1. 主机准备阶段 5.2. 命令发送阶段 5.3. 控制器接收与处理阶段 5.4. 事件过滤与反馈阶段 5.5. 主机处理(主机端) 5.6. 示例代码 六、命令应用场景 …...

第三方Express 路由和路由中间件
文章目录 1、Express 应用使用回调函数的参数: request 和 response 对象来处理请求和响应的数据。2、Express路由1.路由方法2.路由路径3.路由处理程序 3. 模块化路由4. Express中间件1.中间件简介2.中间件分类3.自定义中间件 1、Express 应用使用回调函数的参数&am…...
七、Python —— 元组、集合和字典
文章目录 一、元组1.1、元组的初始化1.2、元组的解包1.3、元组的比较运算1.4、元组的其他操作 二、集合 set2.1、集合的初始化2.2、集合的常用操作2.3、使用 for 循环遍历集合 三、字典 map3.1、字典的初始化3.2、字典的常用操作3.3、使用 for 循环遍历字典 四、补充 一、元组 …...
Aes加解密
加解密概念 加密AES加密填充模式加密模式示例 加密 通过一系列计算将明文转换成一个密文。 加密和解密的对象通常是字节数组(有的语言动态数组类比切片) 加密后的数据,可能有很多是不可读字符。通常会将其转换为可见的字符串。 直接将字节…...
【时时三省】Tessy 故障入侵 使用教程
目录 1,故障入侵 介绍 故障入侵适用场景: 打故障入侵的方法和选项介绍: 2,打单个函数的故障入侵 3,打整体用例的故障入侵 4,一个函数打多个故障入侵 山不在高,有仙则名。水不在深,有龙则灵。 ----CSDN 时时三省 1,故障入侵 介绍 故障入侵适用场景: 故障入侵 …...

.NET 9 AOT的突破 - 支持老旧Win7与XP环境
引言 随着技术的不断进步,微软的.NET 框架在每次迭代中都带来了令人惊喜的新特性。在.NET 9 版本中,一个特别引人注目的亮点是 AOT( Ahead-of-Time)支持,它允许开发人员将应用程序在编译阶段就优化为能够在老旧的 Win…...

CondaValueError: Malformed version string ‘~‘: invalid character(s).
问题描述:在window下使用conda安装任何包都会报错。报错信息是CondaValueError: Malformed version string ~: invalid character(s). 解决办法:把.condarc文件的源地址删除(八成是源地址访问不了了),只保存默认的&am…...

01-Ubuntu24.04LTS上安装PGSQL
目录 一、准备工作 1.1、系统要求 1.2 、更新 Ubuntu 系统 1.3 、安装依赖 1.4 、添加 PostgreSQL 16 软件源 二、安装 PostgreSQL 16 数据库 三、管理 PostgreSQL 服务 四、PostgreSQL 管理操作 4.1 、访问 Postgres 超级用户账户 4.2 、创建数据库并设置管理权限 4…...

Esp32使用micropython基于espnow实现语音对讲机
ESP-NOW协议介绍 ESP-NOW 是乐鑫自主研发的无连接通信协议,具有短数据包传输功能。该协议使多个设备能够以简单的方式相互通信。ESP-NOW 支持以下功能: 加密和未加密的单播通信; 混合加密和未加密的对等设备; 最多可携带 250 字节 的有效载荷; 发送回调功能,可以设置用于…...
Docker 容器隔离关键技术:SELinux
Docker 容器隔离关键技术:SELinux SELinux(Security-Enhanced Linux) 是 Linux 内核中的一项安全机制,用于实现强制访问控制(MAC)。Docker 利用了 SELinux 来增强容器的隔离性,通过对文件、进程…...

Java并发07之ThreadLocal
文章目录 1 ThreadLocal原理2 内部结构3 内存泄露问题4 entry的key为什么被设计为弱引用 1 ThreadLocal原理 ThreadLocal类用来提供线程内部的局部变量。这种变量在多线程环境下访问时能保证各个线程的变量相对独立于其他线程内的变量。ThreadLocal实例通常来说都是private st…...

【单细胞数据库】癌症单细胞数据库CancerSEA
数据库地址:home (hrbmu.edu.cn) Cite Huating Yuan, Min Yan, Guanxiong Zhang, Wei Liu, Chunyu Deng, Gaoming Liao, Liwen Xu, Tao Luo, Haoteng Yan, Zhilin Long, Aiai Shi, Tingting Zhao, Yun Xiao, Xia Li, CancerSEA: a cancer single-cell state atlas…...
Rsa加解密 + 签名验签
Rsa加解密 概述聚合算法名称(用于创建加密器)基本概念填充方式分块加密 基本使用生成密钥加解密创建加密器设置模式(加密)、公钥对明文加密,并对结果进行Base64编码对以上结果,进行解密 设置模式࿰…...

AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...

基于FPGA的PID算法学习———实现PID比例控制算法
基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容:参考网站: PID算法控制 PID即:Proportional(比例)、Integral(积分&…...
mongodb源码分析session执行handleRequest命令find过程
mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...
Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理
引言 Bitmap(位图)是Android应用内存占用的“头号杀手”。一张1080P(1920x1080)的图片以ARGB_8888格式加载时,内存占用高达8MB(192010804字节)。据统计,超过60%的应用OOM崩溃与Bitm…...

Map相关知识
数据结构 二叉树 二叉树,顾名思义,每个节点最多有两个“叉”,也就是两个子节点,分别是左子 节点和右子节点。不过,二叉树并不要求每个节点都有两个子节点,有的节点只 有左子节点,有的节点只有…...
Java + Spring Boot + Mybatis 实现批量插入
在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法:使用 MyBatis 的 <foreach> 标签和批处理模式(ExecutorType.BATCH)。 方法一:使用 XML 的 <foreach> 标签ÿ…...
代码随想录刷题day30
1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...
PAN/FPN
import torch import torch.nn as nn import torch.nn.functional as F import mathclass LowResQueryHighResKVAttention(nn.Module):"""方案 1: 低分辨率特征 (Query) 查询高分辨率特征 (Key, Value).输出分辨率与低分辨率输入相同。"""def __…...

Netty从入门到进阶(二)
二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架,用于…...

android13 app的触摸问题定位分析流程
一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...