设计模式之工厂模式:从汽车工厂到代码工厂
工厂模式概述
想象一下你走进一家4S店准备买车。作为顾客,你不需要知道汽车是如何被制造出来的,你只需要告诉销售顾问:“我想要一辆轿车"或"我想要一辆SUV”,他们就会为你安排相应的车型。这就是工厂模式的核心思想 —— 将对象的创建过程封装起来,让客户端与具体产品的创建逻辑解耦。
在软件开发中,工厂模式就像一个虚拟的4S店。当你的程序需要一个对象时,不需要直接使用new关键字来创建,而是通过工厂类来获取。这样做的好处是,如果将来需要更换对象的创建方式,或者增加新的对象类型,只需要修改工厂类的代码,而不会影响到使用这些对象的代码。
工厂模式通过将对象的创建和使用分离,实现了面向对象设计的一个重要原则:开闭原则(对扩展开放,对修改关闭)。就像4S店可以不断引入新的车型,而不会影响到已有客户的使用体验一样。
工厂模式分类
简单工厂模式
简单工厂就像一家小型的4S店,店里只有一个销售顾问,他根据顾客的需求直接安排相应的车型。在代码实现中,我们会创建一个工厂类,它提供一个创建对象的方法,根据传入的参数来决定创建哪种具体的产品对象。
如:
// 汽车接口
public interface Car {void drive();
}// 具体汽车类
public class SedanCar implements Car {@Overridepublic void drive() {System.out.println("驾驶轿车");}
}public class SUVCar implements Car {@Overridepublic void drive() {System.out.println("驾驶SUV");}
}// 简单工厂类
public class CarFactory {public static Car createCar(String type) {if ("sedan".equals(type)) {return new SedanCar();} else if ("suv".equals(type)) {return new SUVCar();}throw new IllegalArgumentException("不支持的车型类型");}
}
这种模式的使用非常简单:
Car sedanCar = CarFactory.createCar("sedan");
sedanCar.drive();Car suvCar = CarFactory.createCar("suv");
suvCar.drive();
执行结果:
如上示例,在简单工厂模式中,CarFactory类负责创建所有类型的汽车。这种方式适用于产品种类相对固定,创建逻辑不会经常变化的场景。就像一家小型4S店,经营的车型比较固定,不会经常变动。
工厂方法模式
工厂方法模式就像一个汽车制造集团,下设多个专门的工厂,每个工厂专注于生产一种类型的汽车。比如轿车工厂专门生产轿车,SUV工厂专门生产SUV。这样每个工厂都可以根据自己的特点来优化生产流程。
在代码中,我们会定义一个抽象的工厂接口,然后针对不同的产品创建专门的工厂类:
// 抽象工厂
public abstract class CarFactory {abstract Car createCar();
}// 具体工厂
public class SedanFactory extends CarFactory {@Overridepublic Car createCar() {return new SedanCar();}
}public class SUVFactory extends CarFactory {@Overridepublic Car createCar() {return new SUVCar();}
}
使用时,我们先选择对应的工厂,然后创建产品:
CarFactory sedanFactory = new SedanFactory();
Car sedan = sedanFactory.createCar();
sedan.drive();CarFactory suvFactory = new SUVFactory();
Car suv = suvFactory.createCar();
suv.drive();
运行结果:
与简单工厂相比,工厂方法模式将不同产品的创建过程分散到不同的工厂类中,每个工厂类都专注于创建自己的产品。这样在需要增加新产品时,只需要添加新的工厂类,而不需要修改现有的工厂类,更好地符合开闭原则。就像汽车集团可以轻松增加新的生产线,而不会影响现有工厂的运作。
抽象工厂模式
抽象工厂模式就像一个汽车制造集团不仅生产整车,还要生产发动机、车身等配套零部件。每个工厂都能生产一整套相关的产品,这些产品之间相互配套,形成一个产品族。比如轿车工厂生产轿车发动机和轿车车身,SUV工厂生产SUV发动机和SUV车身。如:
// 抽象产品
public interface Engine {void start();
}public interface Body {void assemble();
}// 具体产品
public class SedanEngine implements Engine {@Overridepublic void start() {System.out.println("轿车发动机启动");}
}public class SUVEngine implements Engine {@Overridepublic void start() {System.out.println("SUV发动机启动");}
}public class SedanBody implements Body {@Overridepublic void assemble() {System.out.println("组装轿车车身");}
}public class SUVBody implements Body {@Overridepublic void assemble() {System.out.println("组装SUV车身");}
}// 抽象工厂
public interface CarFactory {Engine createEngine();Body createBody();
}// 具体工厂
public class SedanFactory implements CarFactory {@Overridepublic Engine createEngine() {return new SedanEngine();}@Overridepublic Body createBody() {return new SedanBody();}
}public class SUVFactory implements CarFactory {@Overridepublic Engine createEngine() {return new SUVEngine();}@Overridepublic Body createBody() {return new SUVBody();}
}
测试代码如下:
// 生产轿车系列产品
System.out.println("=== 生产轿车系列 ===");
CarFactory sedanFactory = new SedanFactory();
Engine sedanEngine = sedanFactory.createEngine();
Body sedanBody = sedanFactory.createBody();// 组装轿车
sedanEngine.start(); // 输出:轿车发动机启动
sedanBody.assemble(); // 输出:组装轿车车身System.out.println("\n=== 生产SUV系列 ===");
// 生产SUV系列产品
CarFactory suvFactory = new SUVFactory();
Engine suvEngine = suvFactory.createEngine();
Body suvBody = suvFactory.createBody();// 组装SUV
suvEngine.start(); // 输出:SUV发动机启动
suvBody.assemble(); // 输出:组装SUV车身
运行结果:
工厂模式优缺点
- 简单工厂模式就像一个小型4S店,结构简单,使用方便。它的优点是实现简单,客户端只需要知道产品的参数就可以了;缺点是工厂类的职责相对过重,增加新产品时需要修改工厂类的代码,违反了开闭原则。
- 工厂方法模式像一个汽车制造集团下的多个专业工厂,每个工厂专注于一种产品。它的优点是符合开闭原则,扩展性好,增加新产品只需要增加相应的工厂类;缺点是类的数量会随着产品的增加而增加,增加了系统的复杂度。
- 抽象工厂模式则像一个全产业链的汽车制造集团,可以生产多个产品族。它的优点是能够保证一系列相关产品的配套性,支持产品族的扩展;缺点是抽象层次较高,增加新的产品部件时麻烦,需要修改所有的工厂类。
如何选择工厂模式的实现方式
- 如果你的应用场景简单,产品种类较少且相对稳定,可以选择简单工厂模式。就像开一家小型4S店,只经营几种固定车型。
- 如果产品种类会经常变动,建议使用工厂方法模式。这就像汽车制造集团可以根据市场需求灵活增加新的生产线。
- 如果你需要创建一系列相互关联的产品,那么抽象工厂模式是最好的选择。这适合于像汽车制造这样需要协调多个配套零部件生产的场景。
总结
工厂模式是一种创建型设计模式,它通过将对象的创建与使用分离,提供了一种灵活的对象创建方式。简单工厂适合简单场景,工厂方法适合单个产品的变化,抽象工厂适合产品族的扩展。理解这三种模式的特点和使用场景,可以帮助我们在实际开发中选择最适合的实现方式。
相关文章:

设计模式之工厂模式:从汽车工厂到代码工厂
~犬📰余~ “我欲贱而贵,愚而智,贫而富,可乎? 曰:其唯学乎” 工厂模式概述 想象一下你走进一家4S店准备买车。作为顾客,你不需要知道汽车是如何被制造出来的,你只需要告诉销售顾问&a…...

人脸识别Adaface之libpytorch部署
目录 1. libpytorch下载2. Adaface模型下载3. 模型转换4. c推理4.1 前处理4.2 推理4.3 编译运行4.3.1 写CMakeLists.txt4.3.2 编译4.3.3 运行 1. libpytorch下载 参考: https://blog.csdn.net/liang_baikai/article/details/127849577 下载完成后,将其解…...
vue3+echarts+websocket分时图与K线图实时推送
一、父组件代码: <template> <div class"chart-box" v-loading"loading"> <!-- tab导航栏 --> <div class"tab-box"> <div class"tab-list"> <div v-for"(item, index) in tabList…...
小程序开发实战项目:构建简易待办事项列表
随着移动互联网的飞速发展,小程序以其便捷性、即用即走的特点,成为了连接用户与服务的重要桥梁。无论是电商平台的购物助手,还是餐饮行业的点餐系统,小程序都在各个领域发挥着巨大的作用。 小程序开发基础 1. 小程序简介 小程序是…...

SD Express 卡漏洞导致笔记本电脑和游戏机遭受内存攻击
Positive Technologies 最近发布的一份报告揭示了一个名为 DaMAgeCard 的新漏洞,攻击者可以利用该漏洞利用 SD Express 内存卡直接访问系统内存。 该漏洞利用了 SD Express 中引入的直接内存访问 (DMA) 功能来加速数据传输速度,但也为对支持该标准的设备…...

前端node环境安装:nvm安装详细教程(安装nvm、node、npm、cnpm、yarn及环境变量配置)
需求:在做前端开发的时候,有的时候 这个项目需要 node 14 那个项目需要 node 16,我们也不能卸载 安装 。这岂不是很麻烦。这个时候 就需要 一个工具 来管理我们的 node 版本和 npm 版本。 下面就分享一个 nvm 工具 用来管理 node 版本。 这个…...

java之集合(详细-Map,Set,List)
1集合体系概述 1.1集合的概念 集合是一种容器,用来装数据的,类似于数组,但集合的大小可变,开发中也非常常用。 1.2集合分类 集合分为单列集合和多列集合 Collection代表单列集合,每个元素(数据ÿ…...
常见LeetCode-Saw200
用来记录需要知道见过的题型: LeetCode2-两数相加 说明:以链表的形势给了你每个位的数字,而且是逆序,直接从开头(个位)遍历相加。带上进位即可。有一个为空就直接计算另一个和进位。 LeetCode-3.无重复字符…...

Unity 制作一个视频播放器(打包后,可在外部编辑并放置新的视频)
效果展示: 在这里,我把视频名称(Json)和对应的视频资源都放在了StreamingAssets文件夹下,以便于打包后,客户还可以自己在外部增加、删除、修改对应的视频资料。 如有需要,请联细抠抠。...

MySQL-SQL语句
文章目录 一. SQL语句介绍二. SQL语句分类1. 数据定义语言:简称DDL(Data Definition Language)2. 数据操作语言:简称DML(Data Manipulation Language)3. 数据查询语言:简称DQL(Data Query Language)4. 数据控制语言:简称DCL(Data …...
腾讯微信大数据面试题及参考答案
DNS 协议是否使用 UDP? DNS(Domain Name System)协议主要使用 UDP(User Datagram Protocol),但也会使用 TCP(Transmission Control Protocol)。 UDP 是一种无连接的传输协议,它的特点是简单、高效。DNS 在进行域名解析时,大部分情况下使用 UDP。因为 UDP 的开销小,对…...

Python跳动的爱心
系列文章 序号直达链接表白系列1Python制作一个无法拒绝的表白界面2Python满屏飘字表白代码3Python无限弹窗满屏表白代码4Python李峋同款可写字版跳动的爱心5Python流星雨代码6Python漂浮爱心代码7Python爱心光波代码8Python普通的玫瑰花代码9Python炫酷的玫瑰花代码10Python多…...

计算机启动过程 | Linux 启动流程
注:本文为“计算机启动、 Linux 启动”相关文章合辑。 替换引文部分不清晰的图。 探索计算机的启动过程 Aleksandr Goncharov 2023/04/21 很多人对计算机的启动方式很感兴趣。只要设备开启,这就是魔法开始和持续的地方。在本文中,我们将概…...

反射简单介绍
反射就是从类里拿东西 有的人可能会想为什么不能用io流,从上往下一行一行的读也能获取类中的信息,为什么要用反射呢? 假如我们io流,从左到右一行一行的读取数据,如果碰到局部变量和成员变量同名,怎么区分&a…...

工具篇--GitHub Desktop 使用
文章目录 前言一、GitHub Desktop 的使用:1.1 通过官网下载GitHub Desktop和安装:1.2 安装和使用:1.2.1 填充自己的标识:1.2.3 克隆项目:1.2.4 git 常用忽略项配置: 二、代码的更新和提交:2.1 代…...

单臂路由配置
知识点 单臂路由指在路由器上的一个接口配置子接口(逻辑接口)来实现不同vlan间通信 路由器上的每个物理接口都可以配置多个子接口(逻辑接口) 公司的财务部、技术部和业务部有多台计算机,它们使用一台二层交换机进行互…...

河工oj第七周补题题解2024
A.GO LecturesⅠ—— Victory GO LecturesⅠ—— Victory - 问题 - 软件学院OJ 代码 统计 #include<bits/stdc.h> using namespace std;double b, w;int main() {for(int i 1; i < 19; i ) {for(int j 1; j < 19; j ) {char ch; cin >> ch;if(ch B) b …...
卷积的数学原理与作用
一、一维卷积 (一)定义 数学定义 给定一个输入序列 x [ x 1 , x 2 , ⋯ , x n ] x [x_1,x_2,\cdots,x_n] x[x1,x2,⋯,xn] 和一个卷积核(滤波器) k [ k 1 , k 2 , ⋯ , k m ] k [k_1,k_2,\cdots,k_m] k[k1,k2,⋯,…...
路由介绍.
RIB和FIB Routing Information Base(RIB),即路由信息库,是存储在路由器或联网计算机中的一个电子表格或类数据库,它保存着指向特定网络地址的路径信息,包括路径的路由度量值。RIB的主要目标是实现路由协议…...

CTFshow-命令执行(Web29-40)
CTFshow-命令执行(Web29-40) CTFWeb-命令执行漏洞过滤的绕过姿势_绕过空格过滤-CSDN博客 总结rce(远程代码执行各种sao姿势)绕过bypass_远程命令执行绕过-CSDN博客 对比两者的源代码,我们发现,cat指令把flag.php的内容导出后依…...

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

React第五十七节 Router中RouterProvider使用详解及注意事项
前言 在 React Router v6.4 中,RouterProvider 是一个核心组件,用于提供基于数据路由(data routers)的新型路由方案。 它替代了传统的 <BrowserRouter>,支持更强大的数据加载和操作功能(如 loader 和…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)
🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...

12.找到字符串中所有字母异位词
🧠 题目解析 题目描述: 给定两个字符串 s 和 p,找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义: 若两个字符串包含的字符种类和出现次数完全相同,顺序无所谓,则互为…...
uniapp中使用aixos 报错
问题: 在uniapp中使用aixos,运行后报如下错误: AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...
Typeerror: cannot read properties of undefined (reading ‘XXX‘)
最近需要在离线机器上运行软件,所以得把软件用docker打包起来,大部分功能都没问题,出了一个奇怪的事情。同样的代码,在本机上用vscode可以运行起来,但是打包之后在docker里出现了问题。使用的是dialog组件,…...

CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)
漏洞概览 漏洞名称:Apache Flink REST API 任意文件读取漏洞CVE编号:CVE-2020-17519CVSS评分:7.5影响版本:Apache Flink 1.11.0、1.11.1、1.11.2修复版本:≥ 1.11.3 或 ≥ 1.12.0漏洞类型:路径遍历&#x…...
动态 Web 开发技术入门篇
一、HTTP 协议核心 1.1 HTTP 基础 协议全称 :HyperText Transfer Protocol(超文本传输协议) 默认端口 :HTTP 使用 80 端口,HTTPS 使用 443 端口。 请求方法 : GET :用于获取资源,…...

MySQL 知识小结(一)
一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库,分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷,但是文件存放起来数据比较冗余,用二进制能够更好管理咱们M…...