设计模式之抽象工厂
文章目录
- 一、介绍
- 二、基本组件
- 三、演示案例
- 1. 定义抽象工厂
- 2. 定义抽象产品
- 3. 定义具体工厂
- 4. 定义具体产品
- 5. 代码演示
- 6. 代码改造
- 四、总结
一、介绍
抽象工厂模式(Abstract Factory Pattern)属于创建型设计模式。用于解决比工厂方法设计模式更加复杂的问题。
复杂到哪里了呢?
我们将抽象工厂模式和工厂模式进行简单的比较,或许可以有更好的理解:
- 工厂方法设计模式中,指定工厂只能创建对应的单个产品,是一对一的关系。
- 抽象工厂模式中,不仅需要创建产品的工厂,还多了一个创建工厂的工厂(顶级工厂)。当顶级工厂创建一个工厂时,顶级工厂与工厂是一对一的关系(等同于工厂模式),被创建的工厂可以生产多个产品,因此顶级工厂与产品之间是一对多的关系。
二、基本组件
在我们使用抽象工厂设计模式时,一般需要以下组件:
- 抽象工厂
- 工厂实现
- 抽象产品
- 产品实现
一般来讲,从抽象工厂中获取的对象类型为抽象类型,其具体类型由具体的工厂实现决定。
三、演示案例
唉,到了结婚的年纪了,我们就以结婚为例吧。
1. 定义抽象工厂
结婚是一件十分麻烦的事情,需要准备非常非常多的事情,比如婚车、婚房、婚纱照等等。所以我们以结婚为工厂,以婚车婚房婚纱照为产品。先对结婚这件事情做一个规范的定义。
public interface MarriageFactory {/*** 产品 - 婚车*/Car getCar();/*** 产品 - 婚房*/House getHouse();/*** 产品 - 婚纱照*/Picture getPicture();}
2. 定义抽象产品
-
婚车
public interface Car {/*** 坐婚车*/void drive(); }
-
婚房
public interface House {/*** 买房*/void buyHouse(); }
-
婚纱照
public interface Picture {/*** 照相*/void takePicture(); }
3. 定义具体工厂
我们结婚一般都是要找一个婚庆公司,假设婚庆公司都提供结婚的一条龙服务,包括婚车、婚房、婚纱照等业务,现在我们城里有两家婚庆公司:汤姆婚庆(TomFactory
) 和 杰瑞婚庆(JerryFactory
)。
-
汤姆婚庆(
TomFactory
)汤姆婚庆公司提供具有汤姆特色的业务,如汤姆婚车(
TomCar
)、汤姆婚房(TomHouse
)、汤姆照相(TomPicture
)。public class TomFactory implements MarriageFactory {public TomFactory() {System.out.println("选择了汤姆婚庆公司");}@Overridepublic Car getCar() {return new TomCar();}@Overridepublic House getHouse() {return new TomHouse();}@Overridepublic Picture getPicture() {return new TomPicture();} }
-
杰瑞婚庆(
JerryFactory
)杰瑞婚庆公司提供具有杰瑞特色的业务,如杰瑞婚车(
TomCar
)、杰瑞婚房(TomHouse
)、杰瑞照相(TomPicture
)。public class JerryFactory implements MarriageFactory {public JerryFactory() {System.out.println("选择了杰瑞婚庆公司");}@Overridepublic Car getCar() {return new JerryCar();}@Overridepublic House getHouse() {return new JerryHouse();}@Overridepublic Picture getPicture() {return new JerryPicture();} }
4. 定义具体产品
-
汤姆婚庆公司提供具有汤姆特色的业务,如汤姆婚车(
TomCar
)、汤姆婚房(TomHouse
)、汤姆照相(TomPicture
)。public class TomCar implements Car{/*** 婚车*/@Overridepublic void drive() {System.out.println("汤姆婚车开起来...");} }public class TomHouse implements House{/*** 买房*/@Overridepublic void buyHouse() {System.out.println("汤姆一品房价50w.....");} }public class TomPicture implements Picture{/*** 照相*/@Overridepublic void takePicture() {System.out.println("汤姆照相馆照相.....");} }
-
杰瑞婚庆公司提供的业务具有杰瑞特色,如杰瑞婚车(
TomCar
)、杰瑞婚房(TomHouse
)、杰瑞照相(TomPicture
)。public class JerryCar implements Car{/*** 婚车*/@Overridepublic void drive() {System.out.println("杰瑞婚车开起来...");} }public class JerryHouse implements House{/*** 买房*/@Overridepublic void buyHouse() {System.out.println("杰瑞一品房价30w...");} }public class JerryPicture implements Picture{/*** 照相*/@Overridepublic void takePicture() {System.out.println("杰瑞照相馆照相.....");} }
5. 代码演示
下面我们对上述案例进行代码演示
-
选择杰瑞婚庆公司
public static void main(String[] args) {// 选择杰瑞婚庆公司MarriageFactory factory = new JerryFactory();Car car = factory.getCar();House house = factory.getHouse();Picture picture = factory.getPicture();car.drive();house.buyHouse();picture.takePicture(); }
输出结果:
-
选择汤姆婚庆公司
public static void main(String[] args) {// 选择杰瑞婚庆公司MarriageFactory factory = new TomFactory();Car car = factory.getCar();House house = factory.getHouse();Picture picture = factory.getPicture();car.drive();house.buyHouse();picture.takePicture(); }
输出结果:
6. 代码改造
在上面的测试代码中我们注意到,我们只是对new
婚庆公司的实际类型做了修改,而产品相关代码没有任何改动。于是我们可以将对婚庆公司的实例化过程按照工厂方法设计模式那样转移到工厂中,只需要抽象工厂根据传入的参数返回不同的工厂实例即可。
-
在抽象工厂中添加静态方法
getInstance()
和 枚举类MarriageType
static MarriageFactory getInstance(MarriageType type) {if (type.equals(MarriageType.JERRY)) {return new JerryFactory();}return new TomFactory(); }enum MarriageType {JERRY,TOM; }
-
修改测试代码
public static void main(String[] args) {// 选择杰瑞婚庆公司MarriageFactory factory = MarriageFactory.getInstance(MarriageFactory.MarriageType.JERRY);Car car = factory.getCar();House house = factory.getHouse();Picture picture = factory.getPicture();car.drive();house.buyHouse();picture.takePicture(); }
另外,在静态方法getInstance()
中,我们可以再次结合单例模式来避免频繁实例化婚庆公司对象。
四、总结
- 抽象工厂与工厂方法的最主要区别就是:抽象工厂允许创建多个产品;而工厂方法只允许创建一个产品。
- 该设计模式有一个致命缺点:每当我们在工厂中添加新的产品时,工厂的抽象和具体实现都需要修改。当工厂的具体实现较多时,每一个实现都必须适配新添加的产品。
纸上得来终觉浅,绝知此事要躬行。
————————我是万万岁,我们下期再见————————
相关文章:

设计模式之抽象工厂
文章目录 一、介绍二、基本组件三、演示案例1. 定义抽象工厂2. 定义抽象产品3. 定义具体工厂4. 定义具体产品5. 代码演示6. 代码改造 四、总结 一、介绍 抽象工厂模式(Abstract Factory Pattern)属于创建型设计模式。用于解决比工厂方法设计模式更加复杂的问题。 复杂到哪里了…...

问道管理:数字经济概念走势强劲,竞业达、久其软件等涨停,观想科技等大涨
信创、智慧政务等数字经济概念22日盘中走势微弱,截至发稿,观想科技、慧博云通涨超15%,竞业达、中远海科、久其软件等涨停,云赛智联、延华智能、汇纳科技涨约9%,天玑科技、安硕信息、思特奇、零点稀有涨逾7%。 音讯面上…...

14-redis
一 Redis概述 1 为什么要用NoSQL 单机Mysql的美好年代 在90年代,一个网站的访问量一般都不大,用单个数据库完全可以 轻松应付。在那个时候,更多的都是静态网页,动态交互类型的网站不多。 遇到问题: 随着用户数的增长…...
MySQL——基础——子查询
一、子查询 SQL语句中嵌套SELECT语句,称为嵌套查询,又称子查询 SELECT * from t1 WHERE column1 (SELECT column1 FROM t2); 子查询外部的语句可以是INSERT/UPDATE/DELETE/SELECT中任意一个 根据子查询的结果不同,可以分为: 标…...

业务系统架构实践总结
我从2015年起至今2022年,在业务平台(结算、订购、资金)、集团财务平台(应收应付、账务核算、财资、财务分析、预算)、本地生活财务平台(发票、结算、预算、核算、稽核)所经历的业务系统研发实践…...

Linux学习之DNS服务的原理
DNS服务一些理论 域名系统(Domain Name System,DNS)是互联网的核心应用服务,可以通过IP地址查询到域名,也可以通过域名查询到IP地址。 FQDN(Full Qualified Domain Name)是完全限定域名…...

《Linux内核源码分析》(3)调度器及CFS调度器
《Linux内核源码分析》(3)调度器及CFS调度器 文章目录 《Linux内核源码分析》(3)调度器及CFS调度器一、调度器1、调度器2、调度类sched_class结构体3、优先级4、内核调度策略 二、CFS调度器1、CFS调度器基本原理2、调度子系统各个组件模块3、CFS调度器就绪队列内核源码 一、调度…...
Docker:如何删除已存在的镜像
要删除已存在的 Docker 镜像,您可以使用 docker rmi 命令。 以下是完整的流程 步骤1:停止容器 如容器正在运行需要停止正在运行的 Docker 容器,您可以使用 docker stop 命令。 以下是停止容器的步骤: 首先,使用 do…...
Qt——Qt 开发中所涉及的所有控件(基本控件、容器控件、布局控件、高级控件、其他控件、多媒体控件、定制控件)
Qt 开发中所涉及的所有控件 一、基本控件 二、容器控件 三、布局控件 四、高级控件 五、其他控件 六、多媒体控件 七、定制控件 Qt开发中提供了许多控件(Widgets)供开发者使用,用于构建图形用户界面(GUI)应用程序。以…...

基于Ubuntu坏境下的Suricata坏境搭建
目录 Suricata环境安装 第一步、在 Ubuntu 端点安装 Suricata 1、加入Suricata源 2、更新安装包 3、下载SuricataSuricata 第二步、下载并提取新兴威胁 Suricata 规则集 1、在tmp文件夹下载 Suricata 规则集 如果发现未安装curl,使用apt安装即可:…...
vue3权限管理——(路由权限)动态路由设置
1.大概思路 设置基础路由login和home等页面;登录后从后端获取user,token,rights等数据,并将数据同时存储到vuex和sessionStorage中将后端获取的权限数据(作为不同用户显示不同菜单及不同路由的依据)和路由页面进行映射࿱…...

小程序开发之登录授权
小程序开发登录授权流程 看懂这张图登录授权就没问题了(哈哈哈哈哈) 说明: 调用 wx.login() 获取 临时登录凭证code ,并回传到开发者服务器。 调用 auth.code2Session 接口,换取 用户唯一标识 OpenID 和 会话密钥 sess…...
批量根据excel数据绘制折线图
要批量根据Excel数据绘制折线图,可以使用数据处理和图表绘制软件,例如Microsoft Excel或Python中的Matplotlib库。以下是两种方法: 1. 使用Microsoft Excel: - 打开Excel并导入包含数据的工作表。 - 选择需要绘制折线图的数…...

无锁并发:探秘CAS机制的魔力
😊 作者: 一恍过去 💖 主页: https://blog.csdn.net/zhuocailing3390 🎊 社区: Java技术栈交流 🎉 主题: 无锁并发:探秘CAS机制的魔力 ⏱️ 创作时间: 2…...

iOS App签名与重签名:从开发者证书到重新安装运行
前文回顾: iOS脱壳技术(二):深入探讨dumpdecrypted工具的高级使用方法 iOS逆向:越狱及相关概念的介绍 在本文中,我们将详细介绍iOS应用的签名过程,包括开发者证书的种类、证书与App ID、Provisi…...

vue项目,如何修改Element-Plus等UI组件库的样式,三种方式搞定!!!
前言 我们在学习和使用组件库构建页面的时候,时常会遇到这样的问题。 即,尽管组件库已经提供了较多的功能,来帮助我们构建自定义的效果,但有时仍不能使我们满意。 这个时候我们就不得不修改UI库的样式,来达到想要的状…...

httpd协议与apache
1.http 相关概念 HTTP是处于应用层的协议,使用TCP传输层协议进行可靠的传送。因此,需要特别提醒的是,万维网是基于因特网的一种广泛因特网应用系统,且万维网采用的是HTTP(80/TCP)和 HTTPS(443/…...
Go 自学:文件的写入和读取
首先,使用os.Create()函数建立一个文件。 接着,使用io.WriteString()函数将内容写入文件。 最后,使用os.ReadFile()函数读取文件内容。 注意,这里读取的文件内容是data byte,我们需要使用string()函数将其转换为字符串…...
py 项目上线centos
1 服务器py版本 ps -ef|grep python|grep -v grep 2 2.x版本 安装 PyMySQL pip install PyMySQL0.9.3 3 后台运行py文件 nohup python down.py 1 > log.log 2>&1 & 这个命令将 down.py 程序放入后台运行, 同时将 stdout 输出到 log.log 文件中&…...
【git】would clobber existing tag 报错解决
问题 在用vscode的Git去pull代码的时候git弹窗报错,查看报错日志发现以下内容: > git pull --tags origin feature/xxx-2.0.0 From 173.110.11.22:VV-WORK-FE/vv-desktop* branch feature/xxx-2.0.0 -> FETCH_HEAD! [rejected] …...
Python|GIF 解析与构建(5):手搓截屏和帧率控制
目录 Python|GIF 解析与构建(5):手搓截屏和帧率控制 一、引言 二、技术实现:手搓截屏模块 2.1 核心原理 2.2 代码解析:ScreenshotData类 2.2.1 截图函数:capture_screen 三、技术实现&…...
java 实现excel文件转pdf | 无水印 | 无限制
文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...
连锁超市冷库节能解决方案:如何实现超市降本增效
在连锁超市冷库运营中,高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术,实现年省电费15%-60%,且不改动原有装备、安装快捷、…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
Qt Http Server模块功能及架构
Qt Http Server 是 Qt 6.0 中引入的一个新模块,它提供了一个轻量级的 HTTP 服务器实现,主要用于构建基于 HTTP 的应用程序和服务。 功能介绍: 主要功能 HTTP服务器功能: 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...

【JavaWeb】Docker项目部署
引言 之前学习了Linux操作系统的常见命令,在Linux上安装软件,以及如何在Linux上部署一个单体项目,大多数同学都会有相同的感受,那就是麻烦。 核心体现在三点: 命令太多了,记不住 软件安装包名字复杂&…...

使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
08. C#入门系列【类的基本概念】:开启编程世界的奇妙冒险
C#入门系列【类的基本概念】:开启编程世界的奇妙冒险 嘿,各位编程小白探险家!欢迎来到 C# 的奇幻大陆!今天咱们要深入探索这片大陆上至关重要的 “建筑”—— 类!别害怕,跟着我,保准让你轻松搞…...
C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...