简单工厂模式 (Simple Factory Pattern) 在Spring Boot 中的应用
简单工厂模式(Simple Factory Pattern)虽然不属于 GoF 23 种经典设计模式,但在实际开发中非常常用,尤其是在 Spring Boot 项目中。它提供了一种简单的方式来创建对象,将对象的创建逻辑集中到一个工厂类中。
一、简单工厂模式的定义
简单工厂模式的核心思想是:
- 定义一个工厂类 (Factory Class): 这个工厂类负责创建所有产品对象。
- 工厂类包含一个静态方法 (Static Method): 这个静态方法根据传入的参数(通常是字符串类型或枚举类型),来决定创建哪种具体的产品对象。
- 客户端代码通过工厂类的静态方法获取产品对象: 客户端代码不需要直接使用
new关键字创建对象,而是调用工厂类的静态方法,并传入相应的参数。
简单工厂模式的结构:
- 工厂类 (Factory): 负责创建所有产品对象的类。
- 抽象产品类/接口 (Product): 所有产品对象的共同父类或接口。
- 具体产品类 (ConcreteProduct): 工厂类创建的具体对象类型。
二、简单工厂模式的优缺点
-
优点:
- 简单易用: 实现简单,代码量少,容易理解。
- 封装创建逻辑: 将对象的创建逻辑集中到工厂类中,客户端代码无需关心对象的创建细节。
- 降低耦合度: 客户端代码不直接依赖于具体的产品类,而是依赖于工厂类和抽象产品类/接口。
-
缺点:
- 违反开闭原则: 当需要添加新的产品类型时,需要修改工厂类的代码(例如,添加新的
if-else分支或case分支),这违反了开闭原则(对扩展开放,对修改关闭)。 - 工厂类职责过重: 工厂类负责创建所有产品对象,如果产品种类很多,工厂类的代码会变得很庞大,难以维护。
- 可扩展性差: 由于违反开闭原则,简单工厂模式的可扩展性较差。
- 违反开闭原则: 当需要添加新的产品类型时,需要修改工厂类的代码(例如,添加新的
三、在 Spring Boot 中使用简单工厂模式
在 Spring Boot 中,你可以通过以下方式使用简单工厂模式:
-
直接使用静态方法:
- 创建一个工厂类,并在其中定义一个静态方法,根据参数创建不同的对象。
// 抽象产品接口 interface Product {void doSomething(); }// 具体产品 A class ConcreteProductA implements Product {@Overridepublic void doSomething() {System.out.println("ConcreteProductA");} }// 具体产品 B class ConcreteProductB implements Product {@Overridepublic void doSomething() {System.out.println("ConcreteProductB");} }// 简单工厂类 public class SimpleFactory {public static Product createProduct(String type) {if ("A".equals(type)) {return new ConcreteProductA();} else if ("B".equals(type)) {return new ConcreteProductB();} else {return null; // 或者抛出异常}} }// 使用 public class Client {public static void main(String[] args) {Product productA = SimpleFactory.createProduct("A");productA.doSomething();Product productB = SimpleFactory.createProduct("B");productB.doSomething();} } -
结合 Spring 的
@Component和@Autowired:- 将工厂类注册为 Spring Bean(使用
@Component注解)。 - 在需要使用工厂的地方,通过
@Autowired注入工厂 Bean。 - 这种方式可以更好地利用 Spring 的依赖注入功能。
import org.springframework.stereotype.Component;// ... (Product 接口和 ConcreteProductA, ConcreteProductB 类保持不变) ...// 简单工厂类,使用 @Component 注册为 Spring Bean @Component public class SimpleFactory {public Product createProduct(String type) { // 不需要是静态方法了if ("A".equals(type)) {return new ConcreteProductA();} else if ("B".equals(type)) {return new ConcreteProductB();} else {return null;}} }// 使用 import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class Client {@Autowiredprivate SimpleFactory simpleFactory; // 注入 SimpleFactorypublic void run() {Product productA = simpleFactory.createProduct("A");productA.doSomething();Product productB = simpleFactory.createProduct("B");productB.doSomething();} } - 将工厂类注册为 Spring Bean(使用
-
使用枚举 (Enum) 实现单例的简单工厂:
- 如果你的产品对象是无状态的, 并且每种类型只需要一个实例,可以使用枚举来实现简单工厂,同时保证单例。
interface Product {void doSomething(); }// 具体产品 A class ConcreteProductA implements Product {@Overridepublic void doSomething() {System.out.println("ConcreteProductA");} }// 具体产品 B class ConcreteProductB implements Product {@Overridepublic void doSomething() {System.out.println("ConcreteProductB");} } // 使用枚举实现简单工厂 enum ProductFactory {INSTANCE;public Product createProduct(String type) {if ("A".equals(type)) {return new ConcreteProductA();} else if ("B".equals(type)) {return new ConcreteProductB();} else {return null;}} } //使用 Product product = ProductFactory.INSTANCE.createProduct("A"); -
结合
@Configuration和@Bean:-
你可以使用
@Configuration和@Bean注解来定义工厂方法,并将工厂方法创建的对象注册为 Spring Bean。 这种方式更符合 Spring 的配置风格。import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;// ... (Product 接口和 ConcreteProductA, ConcreteProductB 类保持不变) ...@Configuration public class AppConfig {@Beanpublic Product productA() { // 工厂方法,创建 ConcreteProductAreturn new ConcreteProductA();}@Beanpublic Product productB() { // 工厂方法,创建 ConcreteProductBreturn new ConcreteProductB();}// 你也可以定义一个更通用的工厂方法,根据参数创建不同的 Bean@Beanpublic Product product(@Value("${product.type}") String productType) {if("A".equals(productType)){return new ConcreteProductA();} else {return new ConcreteProductB();}} }
-
四、使用场景
简单工厂模式适用于以下场景:
- 创建对象种类较少: 如果需要创建的对象种类不多,并且创建逻辑比较简单,可以使用简单工厂模式。
- 客户端不需要关心对象的创建细节: 客户端只需要知道如何通过工厂类获取对象即可。
- 对象创建逻辑相对稳定: 如果对象的创建逻辑不经常变化,可以使用简单工厂模式。
五、与 Spring Boot 特性的结合
@Component和@Autowired: 将工厂类注册为 Spring Bean,方便依赖注入。@Configuration和@Bean: 使用@Bean注解定义工厂方法,将工厂方法创建的对象注册为 Spring Bean。@Value: 可以使用@Value注解从配置文件中读取参数,传递给工厂方法,实现更灵活的对象创建。@Conditional: 可以使用@Conditional注解(例如@ConditionalOnProperty、@ConditionalOnClass等)来根据条件决定是否创建某个 Bean,实现更灵活的工厂配置。
六. 简单工厂模式退化为简单工具类
如果简单工厂模式中,工厂类只负责创建对象,没有任何其他的业务逻辑,那么这个工厂类实际上就退化成了一个简单的工具类。在这种情况下,是否使用工厂模式就看个人喜好了,因为并没有带来特别大的好处,也没有明显的坏处。
总结
简单工厂模式是一种简单易用的创建型设计模式,它可以封装对象的创建逻辑,降低代码耦合度。 在 Spring Boot 中,你可以通过多种方式使用简单工厂模式,并结合 Spring 的特性来实现更灵活、更可维护的对象创建。 但是,需要注意简单工厂模式违反开闭原则的缺点,如果需要频繁添加新的产品类型,可以考虑使用工厂方法模式或抽象工厂模式。
相关文章:
简单工厂模式 (Simple Factory Pattern) 在Spring Boot 中的应用
简单工厂模式(Simple Factory Pattern)虽然不属于 GoF 23 种经典设计模式,但在实际开发中非常常用,尤其是在 Spring Boot 项目中。它提供了一种简单的方式来创建对象,将对象的创建逻辑集中到一个工厂类中。 一、简单工…...
《95015网络安全应急响应分析报告(2024)》
2025年2月,95015服务平台发布了最新一期的《95015网络安全应急响应分析报告(2024)》。报告分别从整体形势、受害者特征、攻击者特征等方面,对2024年95015平台接报的739起网络安全应急响应事件展开分析,并给出了7个年度…...
TensorFlow v2.16 Overview
TensorFlow v2.16 Overview 一、模块 Modules二、类 Classes三、函数 Functions TensorFlow v2.16.1 Overview 一、模块 Modules 模块是TensorFlow中组织代码的一种方式,将相关的功能和类封装在一起,方便用户使用和管理。每个模块都提供了特定领域的公共…...
Udp发送和接收数据(python和QT)
服务端代码 (python) import socketdef udp_server(host0.0.0.0, port12345):# 创建一个UDP套接字sock socket.socket(socket.AF_INET, socket.SOCK_DGRAM)# 绑定服务器的IP地址和端口号sock.bind((host, port))print(f"UDP服务器已启动,监听端口 {port}...&…...
element-plus 根据条件显示多选框
代码如下: <el-table :data"pager.lists" selection-change"handleSelectionChange" row-key"id" :tree-props"{ checkStrictly: true }" :cell-class-name"cellClass"> <el-table-column type"s…...
Ubuntu 22.04 Install deepseek
前言 deepseekAI助手。它具有聊天机器人功能,可以与用户进行自然语言交互,回答问题、提供建议和帮助解决问题。DeepSeek 的特点包括: 强大的语言理解能力:能够理解和生成自然语言,与用户进行流畅的对话。多领域知识&…...
DeepSeek赋能智慧文旅:新一代解决方案,重构文旅发展的底层逻辑
DeepSeek作为一款前沿的人工智能大模型,凭借其强大的多模态理解、知识推理和内容生成能力,正在重构文旅产业的发展逻辑,推动行业从传统的经验驱动向数据驱动、从人力密集型向智能协同型转变。 一、智能服务重构:打造全域感知的智…...
小程序的分包
1.分包的概念以及基本用法 2.在小程序项目里面添加自己的分包 3.给分包加上别名 4.查看分包体积大小 5.分包的打包原则 6.分包的引用原则 7.独立分包 8.分包的预下载...
RTSP场景下RTP协议详解及音视频打包全流程
RTSP场景下RTP协议详解及音视频打包全流程 一、RTSP与RTP的关系 RTSP:负责媒体会话控制(DESCRIBE、SETUP、PLAY、PAUSE),通过SDP协商传输参数(端口、编码格式、封装模式)。RTP:实际传输音视频数…...
使用API有效率地管理Dynadot域名,为域名部署DNS安全拓展(DNSSEC)
关于Dynadot Dynadot是通过ICANN认证的域名注册商,自2002年成立以来,服务于全球108个国家和地区的客户,为数以万计的客户提供简洁,优惠,安全的域名注册以及管理服务。 Dynadot平台操作教程索引(包括域名邮…...
如何基于transformers库通过训练Qwen/DeepSeek模型的传统分类能力实现文本分类任务
文章目录 模型与环境准备文档分析源码解读模型训练及推理方式进阶:CPU与显存的切换进阶:多卡数据并行训练🔑 DDP 训练过程核心步骤🚫 DDP 不适用于模型并行⚖️ DDP vs. Model Parallelism⚙️ 解决大模型训练的推荐方法🎉进入大模型应用与实战专栏 | 🚀查看更多专栏…...
开源一款I2C电机驱动扩展板-FreakStudio多米诺系列
总线直流电机扩展板 原文链接: FreakStudio的博客 摘要 设计了一个I2C电机驱动板,通过I2C接口控制多个电机的转速和方向,支持刹车和减速功能。可连接16个扩展板,具有PWM输出、过流过热保护和可更换电机驱动芯片。支持按键控制…...
FFmpeg+WebSocket+JsMpeg实时视频流实现方案
之前写的使用FFmpeg Nginx HLS流媒体播放方案,适合对实时性要求不高的需求,存在延迟,FFmpeg需要将视频流存储到本地文件,而本次方案FFmpeg不需要将视频流存储到本地文件,而是直接将转换后的视频流(如MJPE…...
【Linux】Linux 文件系统—— 探讨软链接(symbolic link)
ℹ️大家好,我是练小杰,周五又到了,明天应该就是牛马的休息日了吧!!😆 前天我们详细介绍了 硬链接的特点,现在继续探讨 软链接的特点,并且后续将添加更多相关知识噢,谢谢…...
排序与算法:插入排序
执行效果 插入排序的执行效果是这样的: 呃……看不懂吗?没关系,接着往下看介绍 算法介绍 插入排序(Insertion Sort)是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,…...
HashMap 详解
一、核心特性 HashMap集合的key是无序不可重复的。 ①无序:插入顺序和取出顺序不一定相同。 ②不可重复:key具有唯一性。 向HashMap集合中put时,key如果重复的话,value会覆盖。 二、HashMap集合的key具有唯一性,向ke…...
DAY07 Collection、Iterator、泛型、数据结构
学习目标 能够说出集合与数组的区别数组:1.是引用数据类型的一种2.可以存储多个元素3.数组的长度是固定的 int[] arr1 new int[10]; int[] arr2 {1,2,3};4.数组即可以存储基本类型的数据,又可以存储引用数据类型的数据int[],double[],String[],Student[]集合:1.是引用数据类…...
计算机网络之物理层——基于《计算机网络》谢希仁第八版
(꒪ꇴ꒪ ),Hello我是祐言QAQ我的博客主页:C/C语言,数据结构,Linux基础,ARM开发板,网络编程等领域UP🌍快上🚘,一起学习,让我们成为一个强大的攻城狮࿰…...
简讯:Rust 2024 edition and v1.85.0 已发布
详见 https://blog.rust-lang.org/2025/02/20/Rust-1.85.0.html 升级方法:rustup update stable...
DeepSeek写俄罗斯方块手机小游戏
DeepSeek写俄罗斯方块手机小游戏 提问 根据提的要求,让DeepSeek整理的需求,进行提问,内容如下: 请生成一个包含以下功能的可运行移动端俄罗斯方块H5文件: 核心功能要求 原生JavaScript实现,适配手机屏幕 …...
脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)
一、数据处理与分析实战 (一)实时滤波与参数调整 基础滤波操作 60Hz 工频滤波:勾选界面右侧 “60Hz” 复选框,可有效抑制电网干扰(适用于北美地区,欧洲用户可调整为 50Hz)。 平滑处理&…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...
visual studio 2022更改主题为深色
visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中,选择 环境 -> 常规 ,将其中的颜色主题改成深色 点击确定,更改完成...
2021-03-15 iview一些问题
1.iview 在使用tree组件时,发现没有set类的方法,只有get,那么要改变tree值,只能遍历treeData,递归修改treeData的checked,发现无法更改,原因在于check模式下,子元素的勾选状态跟父节…...
DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI
前一阵子在百度 AI 开发者大会上,看到基于小智 AI DIY 玩具的演示,感觉有点意思,想着自己也来试试。 如果只是想烧录现成的固件,乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外,还提供了基于网页版的 ESP LA…...
全面解析各类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…...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...
Java线上CPU飙高问题排查全指南
一、引言 在Java应用的线上运行环境中,CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时,通常会导致应用响应缓慢,甚至服务不可用,严重影响用户体验和业务运行。因此,掌握一套科学有效的CPU飙高问题排查方法&…...
MySQL账号权限管理指南:安全创建账户与精细授权技巧
在MySQL数据库管理中,合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号? 最小权限原则…...
招商蛇口 | 执笔CID,启幕低密生活新境
作为中国城市生长的力量,招商蛇口以“美好生活承载者”为使命,深耕全球111座城市,以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子,招商蛇口始终与城市发展同频共振,以建筑诠释对土地与生活的…...
