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

设计模式之抽象工厂

文章目录

  • 一、介绍
  • 二、基本组件
  • 三、演示案例
    • 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)是完全限定域名&#xf…...

《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中将后端获取的权限数据(作为不同用户显示不同菜单及不同路由的依据)和路由页面进行映射&#xff1…...

小程序开发之登录授权

小程序开发登录授权流程 看懂这张图登录授权就没问题了(哈哈哈哈哈) 说明: 调用 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] …...

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 抗噪声…...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄

文|魏琳华 编|王一粟 一场大会,聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中,汇集了学界、创业公司和大厂等三方的热门选手,关于多模态的集中讨论达到了前所未有的热度。其中,…...

C++_核心编程_多态案例二-制作饮品

#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为&#xff1a;煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例&#xff0c;提供抽象制作饮品基类&#xff0c;提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

Leetcode 3576. Transform Array to All Equal Elements

Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接&#xff1a;3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到&#xf…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地

借阿里云中企出海大会的东风&#xff0c;以**「云启出海&#xff0c;智联未来&#xff5c;打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办&#xff0c;现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...

Cinnamon修改面板小工具图标

Cinnamon开始菜单-CSDN博客 设置模块都是做好的&#xff0c;比GNOME简单得多&#xff01; 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...

Map相关知识

数据结构 二叉树 二叉树&#xff0c;顾名思义&#xff0c;每个节点最多有两个“叉”&#xff0c;也就是两个子节点&#xff0c;分别是左子 节点和右子节点。不过&#xff0c;二叉树并不要求每个节点都有两个子节点&#xff0c;有的节点只 有左子节点&#xff0c;有的节点只有…...

如何理解 IP 数据报中的 TTL?

目录 前言理解 前言 面试灵魂一问&#xff1a;说说对 IP 数据报中 TTL 的理解&#xff1f;我们都知道&#xff0c;IP 数据报由首部和数据两部分组成&#xff0c;首部又分为两部分&#xff1a;固定部分和可变部分&#xff0c;共占 20 字节&#xff0c;而即将讨论的 TTL 就位于首…...

【Oracle】分区表

个人主页&#xff1a;Guiat 归属专栏&#xff1a;Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...

论文阅读笔记——Muffin: Testing Deep Learning Libraries via Neural Architecture Fuzzing

Muffin 论文 现有方法 CRADLE 和 LEMON&#xff0c;依赖模型推理阶段输出进行差分测试&#xff0c;但在训练阶段是不可行的&#xff0c;因为训练阶段直到最后才有固定输出&#xff0c;中间过程是不断变化的。API 库覆盖低&#xff0c;因为各个 API 都是在各种具体场景下使用。…...