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

Python设计模式 - 抽象工厂模式

定义

抽象工厂模式是一种创建型设计模式,它提供了一种创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

产品等级结构与产品族

为了更好地理解抽象工厂模式,先引入两个概念:

  1. 产品等级结构:就是产品的继承结构。例如电视机抽象类有A品牌电视机子类和B品牌电视机子类,那么抽象电视机和具体品牌的电视机就构成了一个产品等级结构。
  2. 产品族:同一个工厂生产的,位于不同产品等级结构中的一组产品。例如海尔工厂生产的海尔电视机、海尔电冰箱就构成了一个产品族。

结构

在这里插入图片描述

  • 抽象工厂(Abstract Factory):声明一组用于创建一个产品族产品的工厂方法,每个工厂方法对应一种产品。
  • 具体工厂(Concrete Factory):实现抽象工厂中的工厂方法,这些方法创建的产品构成了一个产品族,每种产品都位于不同的产品等级结构中。
  • 抽象产品(Abstract Product):定义产品对象的接口。
  • 具体产品(Concrete Product):实现产品接口的具体产品对象。

应用场景

  1. 跨平台的产品系列:当需要为不同的平台(如Windows、Mac、Linux)创建一系列相关的产品时,可以使用抽象工厂模式。每个具体工厂类实现工厂方法来创建一个平台的所有产品。例如,跨平台的GUI框架需要针对不同操作系统生成不同风格的按钮、文本框等组件。
  2. 使用多个产品族:系统中有多于一个的产品族,而每次只使用其中某一个产品族,客户端可以通过配置文件等方式来使得用户可以动态改变产品族,也可以很方便地增加新的产品族。例如,窗口中的按钮、文本框可以根据用户的选择按照不同的风格来展示。

优缺点

优点:

  1. 封装对象创建:抽象工厂模式将一系列相关对象的创建封装在一起,客户端无需关心对象的创建过程和具体类型。这减少了代码的耦合度,使系统更易于维护和扩展。
  2. 产品族的一致性:使用一个具体工厂创建的产品对象可以确保属于同一个产品族,且它们之间是兼容的。这避免了客户端在组合不同产品时可能出现的不兼容问题。
  3. 易于扩展:当需要引入新的产品族时,只需添加新的具体工厂类和对应的具体产品类,而不需要修改现有代码。这样能够确保系统的开放-封闭原则,即对扩展开放,对修改封闭。

缺点:

  1. 难以支持新产品类型:如果要添加新的产品等级结构,需要修改抽象工厂类及所有的具体工厂类,这违反了开放-封闭原则,增加维护成本。因此在使用抽象方法模式之前要进行全面考虑,尽量不要在设计完成后增加或删除产品等级结构。

代码示例

from abc import ABC, abstractmethod# 抽象产品 - 按钮
class Button(ABC):@abstractmethoddef click(self):pass# 抽象产品 - 文本框
class TextBox(ABC):@abstractmethoddef input(self, text):pass# 具体产品 - Windows 按钮
class WindowsButton(Button):def click(self):print("Windows Button Clicked")# 具体产品 - Windows 文本框
class WindowsTextBox(TextBox):def input(self, text):print(f"Windows TextBox input: {text}")# 具体产品 - Mac 按钮
class MacButton(Button):def click(self):print("Mac Button Clicked")# 具体产品 - Mac 文本框
class MacTextBox(TextBox):def input(self, text):print(f"Mac TextBox input: {text}")# 抽象工厂
class GUIFactory(ABC):@abstractmethoddef create_button(self):pass@abstractmethoddef create_textbox(self):pass# 具体工厂 - Windows 工厂
class WindowsFactory(GUIFactory):def create_button(self):return WindowsButton()def create_textbox(self):return WindowsTextBox()# 具体工厂 - Mac 工厂
class MacFactory(GUIFactory):def create_button(self):return MacButton()def create_textbox(self):return MacTextBox()# 客户端代码
def client(factory: GUIFactory):button = factory.create_button()textbox = factory.create_textbox()button.click()textbox.input("Hello World")# 使用 Windows 工厂
print("Using Windows Factory:")
client(WindowsFactory())# 使用 Mac 工厂
print("\nUsing Mac Factory:")
client(MacFactory())

抽象工厂模式和工厂方法模式的比较

抽象工厂模式是工厂方法模式的进一步延伸,我们从以下几点进行比较它们:

  1. 系统开销:工厂方法模式中的每个工厂只生产一种产品,可能会导致系统中存在大量的工厂类,会增加系统的开销。而抽象工厂模式将一些相关的产品组成一个“产品族”,由同一个工厂来统一生产,极大地减少了工厂类的数量。
  2. 扩展性:工厂方法模式增加新产品比较容易,只需要增加对应产品类和工厂方法类即可。抽象工厂模式增加新的产品族比较容易,但增加新的产品类型,需要修改抽象工厂类及所有的具体工厂类,扩展性稍差。
  3. 适用场景:工厂方法模式适用于系统只需要一个产品的多种变体的场景,抽象方法模式适用于系统需要创建多个相关产品族的场景。

参考

《设计模式的艺术》

相关文章:

Python设计模式 - 抽象工厂模式

定义 抽象工厂模式是一种创建型设计模式,它提供了一种创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。 产品等级结构与产品族 为了更好地理解抽象工厂模式,先引入两个概念: 产品等级结构:就是产品的…...

【JavaEE初阶】懒汉模式与饿汉模式及指令重排序问题

目录 📕 单例模式 🌳 饿汉模式 🚩 线程安全 🎍 懒汉模式 🚩 懒汉模式-单线程版 🚩 懒汉模式-多线程版 🎄 指令重排序 📕 单例模式 单例模式是一种经典的设计模式,…...

Vue3使用Cascader 级联选择器如何获取值并提交信息

我写了一个用户对象&#xff0c;有address地址字段&#xff0c;我怎么将用户选择的级联数据selectedValue值传给address&#xff0c;并将对象返回给后端&#xff0c;核心代码实现了该问题。 <script> 核心代码&#xff1a; //获取住址并更新给addresslet selectedValue…...

Python面试整理-第三方库

Python社区提供了大量的第三方库,这些库扩展了Python的功能,覆盖了从数据科学到网络应用开发等多个领域。以下是一些非常流行和广泛使用的第三方库: 1. NumPy ● 用途:数值计算。 ● 特点:提供了一个强大的N维数组对象和大量用于数学运算的函数。 ● 应用场景:科学计算、…...

电脑添加虚拟网卡与ensp互联,互访

一、按照过程 1、打开设备管理器 2、点击网络适配器&#xff0c;点击左上角操作&#xff0c;点击“添加过时硬件” 3、下一页 4、选择“安装我手动从列表选择的硬件”&#xff0c;下一页 5、下拉&#xff0c;选择“网络适配器”&#xff0c;下一页 6、厂商选择“Microsoft”&…...

悬而未决:奇怪的不允许跨域CORS policy的问题

我在本地HBuilderX中进行预览写好的前端网页&#xff0c;它里面用了ajax访问了远程服务器的后端API网址&#xff0c;不出意外地报不允许跨域访问的错了&#xff1a;Access to XMLHttpRequest at ‘http://xxx.com/MemberUser/login’ from origin ‘http://mh.com’ has been b…...

索引优化秘籍:SQL Server数据库填充因子的调优艺术

索引优化秘籍&#xff1a;SQL Server数据库填充因子的调优艺术 在SQL Server的性能优化中&#xff0c;索引起着至关重要的作用。而索引填充因子&#xff08;Fill Factor&#xff09;则是控制索引页填充程度的重要参数&#xff0c;它直接影响索引的存储效率和查询性能。本文将深…...

ffmpeg 的内存分配架构

------------------------------------------------------------ author: hjjdebug date: 2024年 08月 01日 星期四 18:00:47 CST descripton: ffmpeg 的内存分配架构1 ------------------------------------------------------------ ffmpeg 的内配分配搞的人晕菜&#…...

Vue+live2d实现虚拟人物互动(一次体验叙述)

目录 故事的开头&#xff1a; 最终的实现效果&#xff1a; 实现步骤&#xff1a; 第一步&#xff1a;下载重要文件 第二步&#xff1a;创建vue项目文件&#xff0c;将刚下载文件拷贝到public目录下 第三步&#xff1a;在index.html文件中引入js 第四步&#xff1a;使用&…...

内联函数的概念和用途以及区别

内联函数&#xff08;Inline Function&#xff09;是C&#xff08;以及C99之后的C语言&#xff09;中的一个特性&#xff0c;旨在通过减少函数调用的开销来提高程序的执行效率。在正常情况下&#xff0c;当程序调用一个函数时&#xff0c;会发生一系列的操作&#xff0c;包括保…...

rust 桌面 sip 软电话(基于tauri 、pjsip库)

本文尝试下rust 的tauri 桌面运用 原因在于体积小 1、pjsip 提供了rust 接口官方的 rust demo 没编译出来 在git找了个sip-phone-rs-master https://github.com/Charles-Schleich/sip-phone-rs 可以自己编译下pjsip lib库替换该项目的lib 2、创建一个tauri demo 引用 [depe…...

Linux 进程优先级、程序地址空间、进程控制

个人主页&#xff1a;仍有未知等待探索-CSDN博客 专题分栏&#xff1a; Linux 目录 一、进程优先级 1、什么是进程优先级&#xff1f; 2、为什么要有优先级&#xff1f; 3、Linux的优先级特点、查看方式 4、命令行参数和环境变量 1.命令行参数 2.环境变量 获取环境变量的…...

学习笔记一

vector 在创建时指定初始大小和初始值&#xff1a; vector<int> a(5, 1) // 包含 5 个整数的 vector&#xff0c;每个值都为 1 可以使用 push_back 方法向 vector 中添加元素&#xff1a; a.push_back(7) // 将整数 7 添加到 vector 的末尾 可以使用 size(…...

Linux中信号的发送及信号的自定义捕捉方法

预备知识&#xff1a; 信号产生时进程早已知道该信号如何处理。 信号产生时进程可能并不能立即处理信号而是等到合适的时候处理。 信号其他相关常见概念 实际执行信号的处理动作称为信号递达(Delivery) 信号从产生到递达之间的状态,称为信号未决(Pending)。 进程可以选择阻…...

yum仓库的制作与使用

目录 前言&#xff1a; 1 查看系统内核 2 获取网络源 3 搭建yum网络仓库 4 rpm包的下载 4.1 将rpm包下载至本地 4.2 对下载的rpm包进行备份 5 制作本地yum源 5.1 软件仓库制作工具createrepo 5.2 使用createrepo创建本地yum仓库 6 搭建docker本地仓库 前言&#x…...

牛客周赛54:D.清楚姐姐跳格子(bfs)

链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 来源&#xff1a;牛客网 题目描述 \,\,\,\,\,\,\,\,\,\,老妪遂递一羊皮卷轴&#xff0c;上面什么都没有&#xff0c;清楚欲问&#xff0c;老妪却缄口不言。           \,\,\,\,\,\,\,\,\,\,清楚性格刚直&…...

用户空间 lmkd

用户空间 lmkd 1、概览1.1 配置lmkd 2、lmkd2.1 lmkd启动2.2 时序图 Android LowMemoryKiller原理分析 AOSP>文档>核心主题低内>存终止守护程序 1、概览 Android Low Memory Killer Daemon &#xff1a;system/memory/lmkd/README.md Android 低内存终止守护程序 (lm…...

二叉树专题

Leetcode 104. 二叉树的最大深度 class Solution { public:int maxDepth(TreeNode* root) {if(!root) return 0;int leftd maxDepth(root -> left) 1;int rightd maxDepth(root -> right) 1;return max(leftd, rightd);} }; Leetcode 100. 相同的树 class Solution…...

Spring MVC 之简介及常见注解

一、什么是 Spring MVC Spring Web MVC 是基于 Servlet API 构建的原始 Web 框架&#xff0c;从一开始就包含在 Spring 框架中。它的正式名称 “Spring Web MVC” 来自其源模块的名称 (Spring-webmvc)&#xff0c;但它通常被称为"Spring MVC"。 什么是Servlet呢? S…...

除了使用本地存储,还有哪些方法可以实现只出现一次的弹窗?

除了使用本地存储&#xff0c;还有以下几种方法可以实现只出现一次的弹窗&#xff1a; 1.使用 Cookie&#xff1a;可以将一个标识符存储在浏览器 Cookie 中&#xff0c;下次用户访问页面时检查 Cookie 中是否存在该标识符&#xff0c;从而判断是否需要显示弹窗。 2.使用服务器端…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现

目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

C++实现分布式网络通信框架RPC(3)--rpc调用端

目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中&#xff0c;我们已经大致实现了rpc服务端的各项功能代…...

<6>-MySQL表的增删查改

目录 一&#xff0c;create&#xff08;创建表&#xff09; 二&#xff0c;retrieve&#xff08;查询表&#xff09; 1&#xff0c;select列 2&#xff0c;where条件 三&#xff0c;update&#xff08;更新表&#xff09; 四&#xff0c;delete&#xff08;删除表&#xf…...

【项目实战】通过多模态+LangGraph实现PPT生成助手

PPT自动生成系统 基于LangGraph的PPT自动生成系统&#xff0c;可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析&#xff1a;自动解析Markdown文档结构PPT模板分析&#xff1a;分析PPT模板的布局和风格智能布局决策&#xff1a;匹配内容与合适的PPT布局自动…...

DingDing机器人群消息推送

文章目录 1 新建机器人2 API文档说明3 代码编写 1 新建机器人 点击群设置 下滑到群管理的机器人&#xff0c;点击进入 添加机器人 选择自定义Webhook服务 点击添加 设置安全设置&#xff0c;详见说明文档 成功后&#xff0c;记录Webhook 2 API文档说明 点击设置说明 查看自…...

【Linux系统】Linux环境变量:系统配置的隐形指挥官

。# Linux系列 文章目录 前言一、环境变量的概念二、常见的环境变量三、环境变量特点及其相关指令3.1 环境变量的全局性3.2、环境变量的生命周期 四、环境变量的组织方式五、C语言对环境变量的操作5.1 设置环境变量&#xff1a;setenv5.2 删除环境变量:unsetenv5.3 遍历所有环境…...

uniapp 小程序 学习(一)

利用Hbuilder 创建项目 运行到内置浏览器看效果 下载微信小程序 安装到Hbuilder 下载地址 &#xff1a;开发者工具默认安装 设置服务端口号 在Hbuilder中设置微信小程序 配置 找到运行设置&#xff0c;将微信开发者工具放入到Hbuilder中&#xff0c; 打开后出现 如下 bug 解…...

小木的算法日记-多叉树的递归/层序遍历

&#x1f332; 从二叉树到森林&#xff1a;一文彻底搞懂多叉树遍历的艺术 &#x1f680; 引言 你好&#xff0c;未来的算法大神&#xff01; 在数据结构的世界里&#xff0c;“树”无疑是最核心、最迷人的概念之一。我们中的大多数人都是从 二叉树 开始入门的&#xff0c;它…...

密码学基础——SM4算法

博客主页&#xff1a;christine-rr-CSDN博客 ​​​​专栏主页&#xff1a;密码学 &#x1f4cc; 【今日更新】&#x1f4cc; 对称密码算法——SM4 目录 一、国密SM系列算法概述 二、SM4算法 2.1算法背景 2.2算法特点 2.3 基本部件 2.3.1 S盒 2.3.2 非线性变换 ​编辑…...

字符串哈希+KMP

P10468 兔子与兔子 #include<bits/stdc.h> using namespace std; typedef unsigned long long ull; const int N 1000010; ull a[N], pw[N]; int n; ull gethash(int l, int r){return a[r] - a[l - 1] * pw[r - l 1]; } signed main(){ios::sync_with_stdio(false), …...