文章目录

    • 一、概念
    • 二、实例分析
    • 三、完整示例

一、概念

  抽象工厂模式是一种创建型设计模式。 提供一个接口用于创建一系列相关或相互依赖的对象,而无需指定它们的具体类。
相比于工厂方法模式,抽象工厂模式不仅仅是创建单一产品,而是一族产品(产品族)。
在这里插入图片描述
抽象工厂模式结构:
在这里插入图片描述

二、实例分析

问题:
假设你正在开发一款家具商店模拟器。 你的代码中包括一些类, 用于表示:

  1. 一系列相关产品, 例如椅子Chair 、 ​ 沙发Sofa和咖啡桌Coffee­Table 。
  2. 系列产品的不同变体。 例如, 你可以使用现代Modern 、 ​ 维多利亚Victorian 、 ​ 装饰风艺术Art­Deco等风格生成 椅子 、沙发和 咖啡桌 。

在这里插入图片描述
你需要设法单独生成每件家具对象, 这样才能确保其风格一致。 如果顾客收到的家具风格不一样, 他们可不会开心。

在这里插入图片描述
此外, 你也不希望在添加新产品或新风格时修改已有代码。 家具供应商对于产品目录的更新非常频繁, 你不会想在每次更新时都去修改核心代码的。

解决方案:
首先, 抽象工厂模式建议为系列中的每件产品明确声明接口 (例如椅子、 沙发或咖啡桌)。 然后, 确保所有产品变体都继承这些接口。 例如, 所有风格的椅子都实现椅子接口; 所有风格的咖啡桌都实现咖啡桌接口, 以此类推。
在这里插入图片描述
接下来, 我们需要声明抽象工厂——包含系列中所有产品构造方法的接口。 例如 create­Chair创建椅子 、 ​ create­Sofa创建沙发和 create­Coffee­Table创建咖啡桌 。 这些方法必须返回抽象产品类型, 即我们之前抽取的那些接口: ​ 椅子 , ​ 沙发和 咖啡桌等等。

那么该如何处理产品变体呢? 对于系列产品的每个变体, 我们都将基于 抽象工厂接口创建不同的工厂类。 每个工厂类都只能返回特定类别的产品, 例如, ​ 现代家具工厂Modern­Furniture­Factory只能创建 现代椅子Modern­Chair 、 ​ 现代沙发Modern­Sofa和 现代咖啡桌Modern­Coffee­Table对象。

客户端代码可以通过相应的抽象接口调用工厂和产品类。 你无需修改实际客户端代码, 就能更改传递给客户端的工厂类, 也能更改客户端代码接收的产品变体。

在这里插入图片描述
设客户端想要工厂创建一把椅子。 客户端无需了解工厂类, 也不用管工厂类创建出的椅子类型。 无论是现代风格, 还是维多利亚风格的椅子, 对于客户端来说没有分别, 它只需调用抽象 椅子接口就可以了。 这样一来, 客户端只需知道椅子以某种方式实现了 sit­On坐下方法就足够了。 此外, 无论工厂返回的是何种椅子变体, 它都会和由同一工厂对象创建的沙发或咖啡桌风格一致。

最后一点说明: 如果客户端仅接触抽象接口, 那么谁来创建实际的工厂对象呢? 一般情况下, 应用程序会在初始化阶段创建具体工厂对象。 而在此之前, 应用程序必须根据配置文件或环境设定选择工厂类别。

代码示例:
抽象产品接口

#include <iostream>
#include <memory>
using namespace std;// 椅子
class Chair {
public:virtual void sitOn() = 0;virtual ~Chair() = default;
};// 沙发
class Sofa {
public:virtual void lieOn() = 0;virtual ~Sofa() = default;
};// 咖啡桌
class CoffeeTable {
public:virtual void putCoffee() = 0;virtual ~CoffeeTable() = default;
};

具体产品实现

// ---------- Art Deco 风格 ----------
class ArtDecoChair : public Chair {
public:void sitOn() override { cout << "坐在 Art Deco 椅子上\n"; }
};class ArtDecoSofa : public Sofa {
public:void lieOn() override { cout << "躺在 Art Deco 沙发上\n"; }
};class ArtDecoCoffeeTable : public CoffeeTable {
public:void putCoffee() override { cout << "在 Art Deco 咖啡桌上放咖啡\n"; }
};// ---------- Victorian 风格 ----------
class VictorianChair : public Chair {
public:void sitOn() override { cout << "坐在 Victorian 椅子上\n"; }
};class VictorianSofa : public Sofa {
public:void lieOn() override { cout << "躺在 Victorian 沙发上\n"; }
};class VictorianCoffeeTable : public CoffeeTable {
public:void putCoffee() override { cout << "在 Victorian 咖啡桌上放咖啡\n"; }
};// ---------- Modern 风格 ----------
class ModernChair : public Chair {
public:void sitOn() override { cout << "坐在 Modern 椅子上\n"; }
};class ModernSofa : public Sofa {
public:void lieOn() override { cout << "躺在 Modern 沙发上\n"; }
};class ModernCoffeeTable : public CoffeeTable {
public:void putCoffee() override { cout << "在 Modern 咖啡桌上放咖啡\n"; }
};

抽象工厂接口

class FurnitureFactory {
public:virtual Chair* createChair() = 0;virtual Sofa* createSofa() = 0;virtual CoffeeTable* createCoffeeTable() = 0;virtual ~FurnitureFactory() = default;
};

具体工厂实现

class ArtDecoFactory : public FurnitureFactory {
public:Chair* createChair() override { return new ArtDecoChair(); }Sofa* createSofa() override { return new ArtDecoSofa(); }CoffeeTable* createCoffeeTable() override { return new ArtDecoCoffeeTable(); }
};class VictorianFactory : public FurnitureFactory {
public:Chair* createChair() override { return new VictorianChair(); }Sofa* createSofa() override { return new VictorianSofa(); }CoffeeTable* createCoffeeTable() override { return new VictorianCoffeeTable(); }
};class ModernFactory : public FurnitureFactory {
public:Chair* createChair() override { return new ModernChair(); }Sofa* createSofa() override { return new ModernSofa(); }CoffeeTable* createCoffeeTable() override { return new ModernCoffeeTable(); }
};

客户端使用

void clientCode(FurnitureFactory* factory) {unique_ptr<Chair> chair(factory->createChair());unique_ptr<Sofa> sofa(factory->createSofa());unique_ptr<CoffeeTable> table(factory->createCoffeeTable());chair->sitOn();sofa->lieOn();table->putCoffee();
}int main() {FurnitureFactory* factory = nullptr;cout << "=== 使用 Art Deco 风格 ===\n";factory = new ArtDecoFactory();clientCode(factory);delete factory;cout << "\n=== 使用 Victorian 风格 ===\n";factory = new VictorianFactory();clientCode(factory);delete factory;cout << "\n=== 使用 Modern 风格 ===\n";factory = new ModernFactory();clientCode(factory);delete factory;return 0;
}

三、完整示例

比如我们要实现一个跨平台的 UI 库,有两种风格:Windows 风格和 Mac 风格,每种风格都包含:

  • 按钮(Button)
  • 文本框(TextBox)

抽象产品

// 抽象按钮
class Button {
public:virtual void paint() = 0;virtual ~Button() = default;
};// 抽象文本框
class TextBox {
public:virtual void show() = 0;virtual ~TextBox() = default;
};

具体产品

// Windows 按钮
class WinButton : public Button {
public:void paint() override { qDebug("Draw Windows Button"); }
};// Windows 文本框
class WinTextBox : public TextBox {
public:void show() override { qDebug("Show Windows TextBox"); }
};// Mac 按钮
class MacButton : public Button {
public:void paint() override { qDebug("Draw Mac Button"); }
};// Mac 文本框
class MacTextBox : public TextBox {
public:void show() override { qDebug("Show Mac TextBox"); }
};

抽象工厂

class GUIFactory {
public:virtual Button* createButton() = 0;virtual TextBox* createTextBox() = 0;virtual ~GUIFactory() = default;
};

具体工厂

class WinFactory : public GUIFactory {
public:Button* createButton() override { return new WinButton(); }TextBox* createTextBox() override { return new WinTextBox(); }
};class MacFactory : public GUIFactory {
public:Button* createButton() override { return new MacButton(); }TextBox* createTextBox() override { return new MacTextBox(); }
};

客户端使用

void clientCode(GUIFactory* factory) {Button* btn = factory->createButton();TextBox* txt = factory->createTextBox();btn->paint();txt->show();delete btn;delete txt;
}int main() {GUIFactory* factory = new WinFactory();clientCode(factory);delete factory;factory = new MacFactory();clientCode(factory);delete factory;return 0;
}

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

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

相关文章

轻量级注意力模型HOTSPOT-YOLO:无人机光伏热异常检测新SOTA,mAP高达90.8%

【导读】 无人机光伏巡检如何更智能、更高效&#xff1f;HOTSPOT-YOLO模型给出了亮眼答案&#xff01;给AI装上“热成像鹰眼”&#xff0c;能精准锁定光伏板上的细微热斑缺陷。它不仅将检测精度&#xff08;mAP&#xff09;提升至90.8%&#xff0c;更在保持实时性的前提下大幅…

CHT共轭传热: 导热系数差异如何影响矩阵系数

文章目录 一、导热系数差异如何影响矩阵系数&#xff1f;二、如何处理系数差异以加速收敛&#xff1f;1. **变量重缩放&#xff08;Scaling of Variables&#xff09;**2. **使用物理型预条件子&#xff08;Physics-based Preconditioning&#xff09;**3. **区域分解法&#x…

Vue Vapor 事件机制深潜:从设计动机到源码解析

基于 vue3.6&#xff08;alpha 阶段&#xff09;及 Vapor 的最新进展撰写&#xff1b;Vapor 仍在演进中&#xff0c;部分实现可能继续优化。TL;DR&#xff08;速览&#xff09; 传统&#xff08;≤3.5&#xff09;&#xff1a;事件以元素为中心绑定&#xff1b;每个元素用 el._…

Day 01(01): Hadoop与大数据基石

目标&#xff1a;建立对大数据生态的整体认知&#xff0c;理解HDFS和MapReduce的核心思想。 8:00-9:30&#xff1a;【视频学习】在B站搜索“Hadoop入门”或“三小时入门大数据”&#xff0c;观看1-2个高播放量的简介视频&#xff0c;了解大数据面临的问题和Hadoop的解决方案。 …

开源 + 免费!谷歌推出 Gemini CLI,Claude Code 的强劲对手

在如今飞速发展的 AI 工具生态中&#xff0c;命令行界面&#xff08;CLI&#xff09;这一开发者与计算机交互的传统方式&#xff0c;正悄然发生着一场颠覆性的变革。2025 年 6 月 25 日&#xff0c;谷歌正式发布开源的 Gemini CLI&#xff0c;这一举措标志着谷歌 Gemini AI 能力…

MacOS - 记录MacOS发烫的好几天 - 幕后黑手竟然是

MacOS - 记录MacOS发烫的好几天 - 幕后黑手竟然是 Mac是不可能出bug的&#xff0c;一定是世界出bug了。 前言 几天前Mac突然开始烫烫的&#xff0c;就这么一烫烫了好几天。这可不行&#xff0c;所以看了下“活动监视器”&#xff0c;发现了一个Code Helper(Plugin)占据200%上下…

Vue基础知识-Vue中:class与:style动态绑定样式

完整源码<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><script src&quo…

终于赶在考试券过期前把Oracle OCP证书考下来了!

&#x1f6a9; 今天终于能松口气了——Oracle OCP证书到手&#xff01; 差点白白浪费一次考试机会&#xff08;1700&#xff09;&#xff01;3月底报名了Oracle OCP&#xff0c;摆烂了大半年&#xff0c;终于是逼着自己在考试券过期前考完了082和083科目&#xff0c;目前已经顺…

Power BI学习笔记-周报销售数据分析

Power BI学习笔记-周报销售数据分析 简介 来自B站的Power BI学习视频的学习笔记。 记录来自B站的Power BI教学视频&#xff0c;由“高级财务BP-Ni”发布&#xff0c;视频发布者主要发布财务类相关的PBI视频&#xff0c;视频长度30分钟左右。 视频链接&#xff1a; 【powerbi周报…

Oracle 数据库与操作系统兼容性指南

前言 作为一个在 Oracle 坑里摸爬滚打多年的老 DBA&#xff0c;最怕听到的就是"这个版本能不能装在这个系统上&#xff1f;"这种问题。昨天又有朋友来问我 Oracle 数据库和操作系统的兼容性&#xff0c;索性把这些年积累的官方兼容性列表整理出来&#xff0c;省得大家…

pytorch初级

本文章是本人通过读《Pytorch实用教程》第二版做的学习笔记&#xff0c;深度学习的核心部分&#xff1a;数据准备 ➡️ 模型构建 ➡️ 模型训练 ➡️ 模型评估与应用。根据上面的思路&#xff0c;我们分为几个部分&#xff1a; 第一部分&#xff1a;PyTorch 基础 - 涵盖了从基本…

UniApp 混合开发:Plus API 从基础到7大核心场景实战的完整指南

在 UniApp 混合开发中&#xff0c;plus API 是连接前端代码与原生设备能力的核心桥梁。基于 5 Runtime&#xff0c;它封装了设备硬件、系统交互、网络通信等近百种原生能力&#xff0c;解决了 UniApp 跨端 API 覆盖不足的问题。但直接使用 plus API 常面临兼容性复杂、回调嵌套…

本周难点问题详细总结

&#x1f4cb; 本周技术问题总结 &#x1f534; 1. 表单校验与用户体验 1.1 表单错误提示不规范 问题&#xff1a;校验失败时缺少页面标识位置&#xff1a;SupplierForm.vue:375代码示例&#xff1a;message.error([基本信息] 表单校验失败&#xff0c;请检查必填字段)影响&…

下一代自动驾驶汽车系统XIL验证方法

摘要自动驾驶汽车测试仍是一个新兴且尚未成熟的过程&#xff0c;全球统一的测试流程尚需时日。实车测试对资源要求极高&#xff0c;因此开发并提升基于虚拟环境的测试方法的效率至关重要。有鉴于此&#xff0c;本文提出一种新颖的 X-in-the-Loop&#xff08;XIL&#xff0c;X 代…

视频数据如何联网共享?

视频数据如何联网共享&#xff1f; 视频联网共享系统&#xff0c;实现前端设备的接入管理以及接入数据的获取。前端设备包括视频设备、卡口设备、Wifi数据采集设备、移动采集设备以及GPS/北斗数据采集设备等。系统实现海量视频数据的快速检索&#xff0c;并为上层数据应用提供视…

Django项目开发全链路:数据库操作、多环境配置、windows/linux项目部署一站式指南

Django项目开发全链路:数据库操作、多环境配置、windows/linux项目部署一站式指南 一、项目初始化 二、创建第一个应用 三、数据库与数据模型的应用 四、创建管理后台用户 五、数据模型与数据库交互之添加 六、数据模型与数据库交互之修改 七、数据模型与数据库交互之查询 八、…

GLib多线程编程实践:从数据结构到线程池的完整指南

引言 GLib是一个功能丰富、跨平台的C程序库,提供了大量高效且经过充分测试的数据结构与算法接口。本文将通过一个完整的实践案例,介绍如何使用GLib实现动态数组、链表、平衡二叉树和线程池,并分享在实际开发中遇到的常见问题及解决方案。 一、GLib核心数据结构实践 1.1 动…

LiteFlow:国产流程编排引擎体验

文章目录一、写在前面二、使用1、Springboot集成2、组件3、表达式4、上下文5、执行器6、脚本组件7、规则配置源8、元数据管理9、异步中的线程池10、动态构造11、决策路由12、生命周期13、其他三、总结一、写在前面 就不做过多介绍了。 官网&#xff1a;https://liteflow.cc/ …

Linux学习:生产者消费者模型

目录1. 生产者消费者模型的相关概念1.1 什么是生产者消费者模型1.2 生产者消费者模型的优势作用2. 多线程简单实现生产者消费者模型2.1 设计方案2.2 代码实现2.2.1 线程类2.2.2 BlockQueue类2.2.3 任务类2.2.4 主干代码1. 生产者消费者模型的相关概念 1.1 什么是生产者消费者模…

《深度学习》卷积神经网络:数据增强与保存最优模型解析及实现

目录 一、数据增强 1. 核心概念 2. 核心目的 3. 常用方法 4. 实现示例&#xff08;基于 PyTorch&#xff09; 5. 自定义数据集加载 二、保存最优模型 1. 核心概念 2. 实现步骤 &#xff08;1&#xff09;定义 CNN 模型 &#xff08;2&#xff09;定义训练与测试函数…