《工厂模式在软件开发中的深度剖析与应用》
工厂模式
在软件开发的领域中,设计模式充当着解决常见问题的高效且可复用的策略角色。其中,工厂模式作为创建对象的重要设计模式,具有不可小觑的应用价值。接下来,我们将深入探讨简单工厂模式、工厂方法模式和抽象工厂模式。
一、简单工厂模式
简单工厂模式虽未被纳入 23 种经典设计模式,但可视为工厂模式的一种简化且特殊的实现方式。
(一)基础版
// 咖啡产品的接口
public interface Coffee {void make();
}// 美式咖啡类,实现 Coffee 接口
public class Americano implements Coffee {@Overridepublic void make() {System.out.println("正在制作美式咖啡");}
}// 摩卡咖啡类,实现 Coffee 接口
public class Mocha implements Coffee {@Overridepublic void make() {System.out.println("正在制作摩卡咖啡");}
}// 卡布奇诺咖啡类,实现 Coffee 接口
public class Cappuccino implements Coffee {@Overridepublic void make() {System.out.println("正在制作卡布奇诺咖啡");}
}// 简单工厂类
public class CoffeeSimpleFactory {/*** 根据传入的字符串类型创建对应的咖啡对象* @param type 咖啡类型的字符串* @return 对应的咖啡对象,如果类型不匹配则返回 null*/public Coffee createCoffee(String type) {if ("americano".equalsIgnoreCase(type)) {return new Americano();} else if ("mocha".equalsIgnoreCase(type)) {return new Mocha();} else if ("cappuccino".equalsIgnoreCase(type)) {return new Cappuccino();}return null;}
}
基础版通过传入字符串参数来决定创建的咖啡产品类型,但这种方式易出现参数输入错误的情况,且新增产品时需在工厂类中添加额外的判断逻辑。
(二)升级版
// 咖啡产品的接口
public interface Coffee {void make();
}// 美式咖啡类,实现 Coffee 接口
public class Americano implements Coffee {@Overridepublic void make() {System.out.println("正在制作美式咖啡");}
}// 摩卡咖啡类,实现 Coffee 接口
public class Mocha implements Coffee {@Overridepublic void make() {System.out.println("正在制作摩卡咖啡");}
}// 卡布奇诺咖啡类,实现 Coffee 接口
public class Cappuccino implements Coffee {@Overridepublic void make() {System.out.println("正在制作卡布奇诺咖啡");}
}// 简单工厂类(升级版)
public class CoffeeSimpleFactory {/*** 使用反射根据传入的咖啡类的 Class 对象创建对应的咖啡对象* @param clazz 咖啡类的 Class 对象* @return 对应的咖啡对象,如果 clazz 为 null 则返回 null* @throws Exception 反射创建对象时可能抛出的异常*/public static Coffee createCoffee(Class<? extends Coffee> clazz) throws Exception {if (clazz!= null) {return clazz.newInstance();}return null;}
}
升级版利用反射机制解决了基础版的参数准确性和扩展性问题。
(三)总结
适用场景:
- 工厂负责创建的对象数量相对较少。
- 客户端只需提供参数,无需关注对象创建的具体流程。
优点:
- 只需传入准确参数,即可轻松获取所需对象,无需知晓内部创建细节。
缺点:
- 工厂类承担过多职责,新增产品类型时需修改判断逻辑,违背了开闭原则。
- 面对复杂的产品结构时,扩展难度较大。
二、工厂方法模式
工厂方法模式明确了一个创建对象的接口,具体由实现该接口的子类来决定实例化的对象类别,将对象的实例化操作推迟至子类中进行。
(一)主要角色
- 抽象工厂(Abstract Factory):定义创建产品的通用接口,为调用者提供访问具体工厂方法的途径,以创建产品。
- 具体工厂(Concrete Factory):负责实现抽象工厂中的抽象方法,从而完成具体产品的创建工作。
- 抽象产品(Product):确立产品的规范和标准,详细描述产品的主要特性与功能。
- 具体产品(Concrete Product):切实实现抽象产品所定义的接口,由具体工厂负责创建,且与具体工厂之间存在一一对应的关系。
(二)代码实现
// 抽象工厂
public interface CoffeeFactory {/*** 创建咖啡对象* @return 抽象的咖啡对象*/Coffee create();
}// 具体工厂 - 拿铁咖啡工厂
public class LatteFactory implements CoffeeFactory {@Overridepublic Coffee create() {return new Latte();}
}// 抽象产品
public interface Coffee {/*** 描述咖啡的制作过程*/void make();
}// 具体产品 - 拿铁咖啡
public class Latte implements Coffee {@Overridepublic void make() {System.out.println("精心调配拿铁咖啡,牛奶与咖啡的完美融合");}
}
(三)总结
适用场景:
- 当创建对象的过程涉及大量重复的代码时。
- 客户端(应用层)不关心产品类实例的创建和实现细节,只关注最终获取到的产品功能。
- 当一个父类通过其子类来决定创建具体的对象类型时。
优点:
- 用户只需关注所需产品对应的具体工厂,无需操心产品的创建细节。
- 新增产品时,符合开闭原则,只需创建新的具体工厂和具体产品类,无需修改现有代码,提高了系统的可扩展性。
缺点:
- 随着产品种类的增加,类的数量会显著增多,导致代码结构的复杂度上升。
- 较高的抽象层次增加了系统的抽象性,对于初学者或不熟悉设计模式的开发者来说,理解和运用的难度较大。
三、抽象工厂模式
抽象工厂模式旨在提供一个创建一系列相关或相互依赖对象的接口,而无需明确指定具体的类。
(一)主要角色
- 抽象工厂(Abstract Factory):提供了创建多个不同产品的接口,这些产品可能属于不同的等级或类别。
- 具体工厂(Concrete Factory):实现了抽象工厂中的抽象方法,负责生成具体的一组相关或相互依赖的产品。
- 抽象产品(Product):定义了产品的基本规范和主要特性,一个抽象工厂可能关联多个不同的抽象产品。
- 具体产品(Concrete Product):实现了抽象产品所定义的接口,由具体的工厂进行创建,且与具体工厂之间存在多对一的关系。
(二)代码实现
// 咖啡店 抽象工厂
public interface CoffeeShopFactory {/*** 创建咖啡产品* @return 具体的咖啡产品*/Coffee createCoffee();/*** 创建甜点产品* @return 具体的甜点产品*/Dessert createDessert();
}// 美式风格工厂
public class AmericanFactory implements CoffeeShopFactory {@Overridepublic Coffee createCoffee() {return new Americano();}@Overridepublic Dessert createDessert() {return new Cheesecake();}
}// 意式风格工厂
public class ItalyFactory implements CoffeeShopFactory {@Overridepublic Coffee createCoffee() {return new Cappuccino();}@Overridepublic Dessert createDessert() {return new Tiramisu();}
}// 抽象产品 - 咖啡
public interface Coffee {/*** 描述咖啡的制作过程*/void make();
}// 具体产品 - 美式咖啡
public class Americano implements Coffee {@Overridepublic void make() {System.out.println("精心调制美式咖啡,浓郁醇厚");}
}// 抽象产品 - 甜点
public interface Dessert {/*** 描述甜点的品尝方式*/void enjoy();
}// 具体产品 - 芝士蛋糕
public class Cheesecake implements Dessert {@Overridepublic void enjoy() {System.out.println("尽情享受美味的芝士蛋糕,香甜可口");}
}
(三)总结
产品族:指一系列紧密相关、相互关联的产品集合。
产品等级:指处于同一继承体系或具有相似性质的产品类别。
适用场景:
- 当客户端(应用层)不依赖于产品类实例的创建和实现细节时。
- 强调一系列相关的产品对象(属于同一产品族)需协同工作,且创建这些对象的过程存在大量重复代码时。
- 当需要为客户端提供一个统一的产品类库,使所有产品以相同的接口呈现,从而降低客户端对具体实现的依赖时。
优点:
- 能够确保当一个产品族中的多个对象协同工作时,客户端始终使用来自同一产品族的对象,保证了产品的一致性和协调性。
缺点:
- 当产品族中需要新增一个产品时,所有相关的工厂类都需要进行修改,这可能导致较大的代码改动和潜在的风险。
相关文章:
《工厂模式在软件开发中的深度剖析与应用》
工厂模式 在软件开发的领域中,设计模式充当着解决常见问题的高效且可复用的策略角色。其中,工厂模式作为创建对象的重要设计模式,具有不可小觑的应用价值。接下来,我们将深入探讨简单工厂模式、工厂方法模式和抽象工厂模式。 一…...
双向通信之Websocket
介绍 Websocket是一种在单个TCP连接上进行全双工通信的协议。与传统的HTTP协议不同,websocket允许客户端与服务器之间的双向通信,可以在同一条连接上进行多次消息的快速传递。我之前在做一个线上刷题网站的时候,需要设计一个社区讨论模块&am…...

git学习使用碰到的问题1
本来在B站上看到的关于stash的使用时视频末尾讲到git stash drop 编号 会删除暂存记录 确实也是这么回事,但是末尾说到git stash pop 编号时up主说在恢复工作进度的时候我们可以直接删除掉这个工作记录可以直接使用 git stash pop stash{0} 使用完以后却出现了如上图…...
JavaScript初级——Math
一、Math 和其他的对象不同,它不是一个构造函数。它属于一个工具类,不用创建对象,里边封装了数学运算相关的属性和方法。 比如: Math.PI 表示圆周率。 二、Math.abs() —— 可以用来计算一个数的绝对值。 三…...

ffmpeg的基础命令
文章目录 ffmpeg/ffplay/ffprobe区别ffmpeg 的作用ffplay的作用ffprobe的作用 ffmpeg使用概述功能概述转码过程简单使用FFMPEG -i常用的 -i例子 ff***工具之间共享的选项ffmpeg主要选项ffmpeg提取音视频数据ffmpeg命令修改原有的视频格式ffmpeg命令裁剪和合并视频拼接视频的方式…...
二建机电工程实务试题内附答案
1.下列有色金属材料中,不属于铜合金的是()。 A.紫铜 B.青铜 C.黄铜 D.白铜【答案】A 2.用于完成介质间热量交换的换热设备是()。 A.分离器 B.反应器 C.冷凝器 D.分解锅【答案】C 3.工程测量的核心是()。 A.测量精度 B.设计要求 C.减少误差累积 D.检核【答案】D 4.吊…...
Redis的热key以及Big(大)key是什么?如何解决Redis的热key以及Big(大)key问题?
一、先讲讲什么是redis的热key问题 在Redis中,我们把访问频率高的Key,称为热Key。比如突然有几十万的请求去访问redis中某个特定的Key,那么这样会造成redis服务器短时间流量过于集中,很可能导致redis的服务器宕机。那么接下来对这…...
django学习入门系列之第九点《MySQL命令介绍一》
文章目录 MySQL命令数据库的管理(文件夹)查看现在已有的数据库(文件夹)创建数据库(文件夹)删除数据库(文件夹)进入数据库(文件夹)查看文件夹下所有的数据表&a…...
Mysql面试一
目录 一、事务的四大特性(ACID): 脏读 不可重复读 幻读 隔离性与隔离级别 数据库的三大范式 第一范式。确保数据表中的每个字段都是不可分割的最小单位,即原子性。这意味着表中的每一列都应代表一个独立的数据单元ÿ…...

模型优化之剪枝
文章目录 什么是神经网络剪枝剪枝的好处不同粒度的剪枝剪枝的分类非结构化剪枝结构化剪枝 哪些层的参数更容易被剪掉剪枝效果 什么是神经网络剪枝 神经网络剪枝 在训练期间删除连接密集张量将变得稀疏(用零填充)可以通过结构化块( n m nm nm&…...

JVM的组成
JVM 运行在操作系统之上 java二进制字节码文件的运行环境 JVM的组成部分 java代码在编写完成后编译成字节码文件通过类加载器 来到运行数据区,主要作用是加载字节码到内存 包含 方法区/元空间 堆 程序计数器,虚拟机栈,本地方法栈等等 随后来到执行引擎,主要作用是翻译字…...
快速上手 iOS Protocol Buffer
快速上手 iOS Protocol Buffer | 来自缤纷多彩的灰 本文主要介绍在 iOS 开发中如何快速上手使用 Protobuf。更多关于 Protobuf 的介绍和相关的功能 api,读者可自行查阅官网。 Protocol Buffer(简称 Protobuf)是一种由Google开发的语言中立、…...
每天一个数据分析题(四百八十)- 线性回归建模
关于线性回归建模,线性回归模型假设说法不正确的是? A. 因变量和自变量要有因果关系 B. 残差均值为0 C. 残差服从正态分布 D. 自变量不存在共线性 数据分析认证考试介绍:点击进入 题目来源于CDA模拟题库 点击此处获取答案 数据分析专…...

电动汽车和混动汽车DC-DC转换器的创新设计与测试方法
汽车 DC-DC 转换器市场规模将达到187亿美元,年复合增长率为10%。 DC-DC 转换器是汽车的重要组成部分,它可以通过电压转换为各种车载系统供电,例如日益复杂的车载信息娱乐系统、使用驾驶辅助系统(ADAS)实现的增强安全功…...

OriginPro快速上手指南:数据可视化与分析的利器
目录 OriginLab - Origin and OriginPro - Data Analysis and Graphing Softwarehttps://www.originlab.com/编辑 一、安装与界面概览 安装 界面概览 二、基础操作 数据输入 创建图表 三、高级功能 数据分析 自动化与脚本 Origin 提供了几个小工具 四、技巧与提示…...

缓存学习
缓存基本概念 概念 对于缓存,最普遍的理解是能让打开某些页面速度更快的工具。从技术角度来看,其本质上是因为缓存是基于内存建立的,而内存的读写速度相比之于硬盘快了xx倍,因此用内存来代替硬盘作为读写的介质当然能大大提高访…...

亚世光电:消费电子年度表演
机圈风云再起,消费电子乘风而起? 今天我们来聊——亚世光电 最近,华为mate60突然降价,被大家怀疑是为新品上市做准备,算算时间,下半年的消费电子大战也即将拉开帷幕,而亚世光电所在的光电显示领…...

AI 工程应用 建筑表面检测及修复
文章目录 1 项目概述(必写):2 技术方案与实施步骤2.1 模型选择(必写):2.2 数据的构建:2.3 功能整合(进阶): 3 实施步骤:3.1 环境搭建(…...

Qt-Qt中的小事项(7)
目录 命名风格 快捷键 查询文档 坐标系 代码理解 move 命名风格 这个也是老生常谈的问题了,入乡随俗就好啦 快捷键 这里是一些常用的快捷键,用多了自然就熟悉了 • 注释:ctrl/ • 运行:ctrlR • 编译:ctrlB …...
Android MediaRecorder 视频录制及报错解决
目录 一、start failed: -19 二、使用MediaRecorder录制视频 2.1 申请权限 2.2 布局文件 2.3 MediaRecordActivity 2.4 运行结果 三、拓展 3.1 录制视频模糊(解决) 3.2 阿里云OSS上传文件 3.2.1 权限(刚需) 3.2.2 安装SDK 3.2.3 使用 相关链接 一、start failed…...

stm32G473的flash模式是单bank还是双bank?
今天突然有人stm32G473的flash模式是单bank还是双bank?由于时间太久,我真忘记了。搜搜发现,还真有人和我一样。见下面的链接:https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...
golang循环变量捕获问题
在 Go 语言中,当在循环中启动协程(goroutine)时,如果在协程闭包中直接引用循环变量,可能会遇到一个常见的陷阱 - 循环变量捕获问题。让我详细解释一下: 问题背景 看这个代码片段: fo…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...

大数据零基础学习day1之环境准备和大数据初步理解
学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...

【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...

ElasticSearch搜索引擎之倒排索引及其底层算法
文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...
【JavaSE】绘图与事件入门学习笔记
-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角,以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向,距离坐标原点x个像素;第二个是y坐标,表示当前位置为垂直方向,距离坐标原点y个像素。 坐标体系-像素 …...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?
在大数据处理领域,Hive 作为 Hadoop 生态中重要的数据仓库工具,其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式,很多开发者常常陷入选择困境。本文将从底…...