简单工厂模式 (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 项目中。它提供了一种简单的方式来创建对象,将对象的创建逻辑集中到一个工厂类中。 一、简单工…...
Python简单使用MinerU
Python简单使用MinerU 1 简介 MinerU是国产的一款将PDF转化为机器可读格式的工具(如markdown、json),可以很方便地抽取为任意格式。目前支持图像(.jpg及.png)、PDF、Word(.doc及.docx)、以及P…...
使用AI创建流程图和图表的 3 种简单方法
你可能已经尝试过使用 LLMs 生成图像,但你有没有想过用它们来创建 流程图和图表?这些可视化工具对于展示流程、工作流和系统架构至关重要。 通常,在在线工具上手动绘制图表可能会耗费大量时间。但你知道吗?你可以使用 LLMs 通过简…...
ImportError: cannot import name ‘FixtureDef‘ from ‘pytest‘
错误信息表明 pytest 在尝试导入 FixtureDef 时出现了问题。通常是由于 pytest 版本不兼容 或 插件版本冲突 引起的。以下是详细的排查步骤和解决方案: 1. 检查 pytest 版本 首先,确认当前安装的 pytest 版本。某些插件可能需要特定版本的 pytest 才能…...
机器学习实战(7):聚类算法——发现数据中的隐藏模式
第7集:聚类算法——发现数据中的隐藏模式 在机器学习中,聚类(Clustering) 是一种无监督学习方法,用于发现数据中的隐藏模式或分组。与分类任务不同,聚类不需要标签,而是根据数据的相似性将其划…...
z-score算法
z-score算法原理参考网址 https://blog.csdn.net/m0_59596937/article/details/128378641 具体实现代码如下: import numpy as npclass ZScoreOutlierDetector:def __init__(self, threshold3):"""构造函数"""self.threshold thre…...
企业级RAG开源项目分享:Quivr、MaxKB、Dify、FastGPT、RagFlow
企业级 RAG GitHub 开源项目深度分享:Quivr、MaxKB、Dify、FastGPT、RagFlow 及私有化 LLM 部署建议 随着生成式 AI 技术的成熟,检索增强生成(RAG)已成为企业构建智能应用的关键技术。RAG 技术能够有效地将大型语言模型ÿ…...
open webui 部署 以及解决,首屏加载缓慢,nginx反向代理访问404,WebSocket后端服务器链接失败等问题
项目地址:GitHub - open-webui/open-webui: User-friendly AI Interface (Supports Ollama, OpenAI API, ...) 选择了docker部署 如果 Ollama 在您的计算机上,请使用以下命令 docker run -d -p 3000:8080 --add-hosthost.docker.internal:host-gatewa…...
C++ 智能指针 unique_ptr shared_ptr weak_ptr小练习
智能指针是 C11 引入的一项重要特性,它可以帮助我们管理动态分配的内存,自动释放内存,避免内存泄漏和悬空指针的问题。智能指针有三种常用类型:std::unique_ptr、std::shared_ptr 和 std::weak_ptr。 为了帮助你熟悉智能指针的使…...
Netstat(Network Statistics)网络工具介绍
Netstat 工具详细介绍及常见指令应用 Netstat(Network Statistics)是一个常用的命令行工具,用于显示网络连接、路由表、接口统计信息、伪装连接等信息。它可以帮助用户监控计算机的网络状态,尤其在诊断网络问题时非常有用。Netst…...
内容中台架构下智能推荐系统的算法优化与分发策略
内容概要 在数字化内容生态中,智能推荐系统作为内容中台的核心引擎,承担着用户需求与内容资源精准匹配的关键任务。其算法架构的优化路径围绕动态特征建模与多模态数据融合展开,通过深度强化学习技术实现用户行为特征的实时捕捉与动态更新&a…...
React 高阶组件的优缺点
React 高阶组件的优缺点 优点 1. 代码复用性高 公共逻辑封装:当多个组件需要实现相同的功能或逻辑时,高阶组件可以将这些逻辑封装起来,避免代码重复。例如,多个组件都需要在挂载时进行数据获取操作,就可以创建一个数…...
最新版IDEA下载安装教程
一、下载IDEA 点击前往官网下载 或者去网盘下载 点击前往百度网盘下载 点击前往夸克网盘下载 进去后点击IDEA 然后点击Download 选择自己电脑对应的系统 点击下载 等待下载即可 二、安装IDEA 下载好后双击应用程序 点击下一步 选择好安装目录后点击下一步 勾选这两项后点击…...
DeepSeek最新开源动态:核心技术公布
2月21日午间,DeepSeek在社交平台X发文称,从下周开始,他们将开源5个代码库,以完全透明的方式与全球开发者社区分享他们的研究进展。并将这一计划定义为“Open Source Week”。 DeepSeek表示,即将开源的代码库是他们在线…...
《炒股养家心法.pdf》 kimi总结
《炒股养家心法.pdf》这篇文章详细阐述了一位超级游资炒股养家的心得与技巧,展示了其从40万到10亿的股市传奇。以下是文章中炒股技巧和心得的详细总结: 1.核心理念 市场情绪的理解:炒股养家强调,股市的本质是群体博弈,…...
运维脚本——8.证书自动化管理
场景:自动化SSL/TLS证书的申请、续期和部署,避免证书过期导致服务中断。 示例:使用Shell脚本配合Lets Encrypt的Certbot工具自动续期证书。 #!/bin/bash # 自动续期Lets Encrypt证书并重启服务 certbot renew --quiet --post-hook "syst…...
RDMA ibverbs_API功能说明
设备管理 获取当前活动网卡 返回当前rdma设备列表 struct ibv_device **ibv_get_device_list(int *num_devices);//使用 struct ibv_device **dev_list ibv_get_device_list(NULL);获取网卡名 返回网卡名字字符串:如"mlx5_0",一般通过网卡…...
第15届 蓝桥杯 C++编程青少组中/高级选拔赛 202401 真题答案及解析
第 1 题 【 单选题 】 表达式117 % 16 的结果是( )。 A:0 B:5 C:7 D:10 解析: % 是取模运算符,用于计算两个数相除后的余数。 计算 117 / 16,结果是 7,余数是 5。因此,117 % 16 = 5。答案: B 第 2 题 【 单选题 】 下列选项中,字符数组定义正确的是( …...
【R语言】绘图
一、散点图 散点图也叫X-Y图,它将所有的数据以点的形式展现在坐标系上,用来显示变量之间的相互影响程度。 ggplot2包中用来绘制散点图的函数是geom_point(),但在绘制前需要先用ggplot()函数指定数据集和变量。 下面用mtcars数据集做演示&a…...
Linux基本指令(三)+ 权限
文章目录 基本指令grep打包和压缩zip/unzipLinux和windows压缩包互传tar(重要)Linux和Linux压缩包互传 bcuname -r常用的热键关机外壳程序 知识点打包和压缩 Linux中的权限用户权限 基本指令 grep 1. grep可以过滤文本行 done用于标记循环的结束&#x…...
容器化部署tomcat
容器化部署tomcat 需求在docker容器中部署tomcat,并通过外部机器访问tomcat部署的项目 容器化部署要先装好docker容器(docker安装配置) 实现步骤: 拉取tomcat docker pull tomcat用于列出本地Docker主机上存储的所有镜像 docker images在root目录里面创建tomc…...
vscode软件中引入vant组件
一、vant简介 Vant 是一个轻量、可靠的移动端组件库,于 2017 年开源。 目前 Vant 官方提供了 Vue 2 版本、Vue 3 版本和微信小程序版本,并由社区团队维护 React 版本和支付宝小程序版本。 官网:介绍 - Vant Weapp 里面的快速上手的教程&a…...
DeepSeek vs ChatGPT:AI 领域的华山论剑,谁主沉浮?
一、引言 在当今科技飞速发展的时代,人工智能(AI)已然成为推动各领域变革的核心力量。而在人工智能的众多分支中,自然语言处理(NLP)因其与人类日常交流和信息处理的紧密联系,成为了最受瞩目的领…...
Ubuntu 22.04 Install deepseek
前言 deepseekAI助手。它具有聊天机器人功能,可以与用户进行自然语言交互,回答问题、提供建议和帮助解决问题。DeepSeek 的特点包括: 强大的语言理解能力:能够理解和生成自然语言,与用户进行流畅的对话。多领域知识&…...
如何将公钥正确添加到服务器的 authorized_keys 文件中以实现免密码 SSH 登录
1. 下载密钥文件 2. RSA 解析 将 id_ed25519 类型的私钥转换为 RSA 类型,要将 ED25519 私钥转换为 RSA 私钥,需要重新生成一个新的 RSA 密钥对。 步骤: 生成新的 RSA 密钥对 使用 ssh-keygen 来生成一个新的 RSA 密钥对。比如,执…...
深入理解设计模式之解释器模式
深入理解设计模式之解释器模式 在软件开发的复杂世界中,我们常常会遇到需要处理特定领域语言的情况。比如在开发一个计算器程序时,需要解析和计算数学表达式;在实现正则表达式功能时,要解析用户输入的正则表达式来匹配文本。这些场景都涉及到对特定语言的解释和执行,而解…...
【WebGL】attribute方式实例化绘制
背景 一般有attribute和uniform两种方式进行实例化绘制 attribute方式实例化 这里需要注意 bufferData和bufferSubData方式的用法顺序和参数 gl.bufferData(target, sizeOrData, usage); sizeOrData(实例化配合bufferSubData 更新数据一般使用这种先)…...
线代[8]|北大丘维声教授《怎样学习线性代数?》(红色字体为博主注释)
文章目录 说明一、线性代数的内容简介二、学习线性代数的用处三、线性代数的特点四、学习线性代数的方法五、更新时间记录 说明 文章中红色字体为博主敲录完丘教授这篇文章后所加,刷到这篇文章的读者在首次阅读应当跳过红色字体,先通读一读文章全文&…...
光明谷推出AT指令版本的蓝牙音箱SOC 开启便捷智能音频开发新体验
前言 在蓝牙音箱市场竞争日益激烈的当下,开发一款性能卓越且易于上手的蓝牙音箱,成为众多厂商追求的目标。而光明谷科技有限公司推出的 AT 指令版本的蓝牙音箱 SOC,无疑为行业带来了全新的解决方案,以其诸多独特卖点,迅…...
C#从入门到精通(34)—如何防止winform程序被同时打开多次
前言: 大家好,我是上位机马工,硕士毕业4年年入40万,目前在一家自动化公司担任软件经理,从事C#上位机软件开发8年以上!我们在开发上位机软件的过程中,评判一个人软件写的好不好,有一…...
