设计模式之抽象工厂
文章目录
- 一、介绍
 - 二、基本组件
 - 三、演示案例
 - 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()和 枚举类MarriageTypestatic 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] …...
华为云AI开发平台ModelArts
华为云ModelArts:重塑AI开发流程的“智能引擎”与“创新加速器”! 在人工智能浪潮席卷全球的2025年,企业拥抱AI的意愿空前高涨,但技术门槛高、流程复杂、资源投入巨大的现实,却让许多创新构想止步于实验室。数据科学家…...
Spark 之 入门讲解详细版(1)
1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室(Algorithms, Machines, and People Lab)开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目,8个月后成为Apache顶级项目,速度之快足见过人之处&…...
理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...
【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...
AI书签管理工具开发全记录(十九):嵌入资源处理
1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...
【Redis】笔记|第8节|大厂高并发缓存架构实战与优化
缓存架构 代码结构 代码详情 功能点: 多级缓存,先查本地缓存,再查Redis,最后才查数据库热点数据重建逻辑使用分布式锁,二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...
Windows安装Miniconda
一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...
springboot 日志类切面,接口成功记录日志,失败不记录
springboot 日志类切面,接口成功记录日志,失败不记录 自定义一个注解方法 import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;/***…...
面试高频问题
文章目录 🚀 消息队列核心技术揭秘:从入门到秒杀面试官1️⃣ Kafka为何能"吞云吐雾"?性能背后的秘密1.1 顺序写入与零拷贝:性能的双引擎1.2 分区并行:数据的"八车道高速公路"1.3 页缓存与批量处理…...
