设计模式 创建型 工厂模式(Factory Pattern)与 常见技术框架应用 解析

在这里插入图片描述

工厂模式(Factory Pattern)是一种创建型设计模式,它提供了一种封装对象创建过程的方式,使得对象的创建与使用分离,从而提高了系统的可扩展性和可维护性。

一、核心思想

工厂模式的核心思想是将“实例化对象”的操作与“使用对象”的操作分开,将实例化对象的责任交给专门的工厂类负责。这样可以降低系统的耦合度,提高系统的可扩展性和可维护性。

二、定义与结构

1、定义

工厂模式稳坐创建型设计模式的头把交椅,其核心使命是匠心独运地架构一种精妙绝伦的机制,使得对象的创建环节与使用环节能够井水不犯河水地分离开来。具体而言,它仰仗一个或多个专业打造的工厂类,依据预设的特定规则、传入的精准参数或者实时监测到的系统条件,英明决断究竟该打造何种类型的对象,并将成品对象精准无误地交付给翘首以盼的代码模块。

2、工厂模式有两种主要形式

2.1、简单工厂模式:不作为设计模式被正式认可,但它是一个常用的概念。它不是严格的设计模式,因为它违反了开闭原则(对扩展开放,对修改关闭)。简单工厂模式包含:

  • 工厂类:负责接收所有创建请求。
  • 产品接口或抽象类:定义产品的公共接口。
  • 具体产品类:实现产品接口的具体产品。

2.2、工厂方法模式:是一种更正式的设计模式,它解决了简单工厂模式的问题,并且遵循开闭原则。它包括:

  • 抽象工厂(Abstract Factory):声明了一个创建产品的接口,其中的工厂方法用于实例化一个产品。通常以抽象类或者接口这般高冷姿态示人,它宛如一位高瞻远瞩的总设计师,定义了一系列用于创建紧密相关的一系列产品对象的抽象方法集。这些抽象方法如同精密模具,为后续衍生出的具体工厂子类勾勒出清晰、统一且规范的创建框架,确保在整个产品家族创建过程中的规范性与一致性得以严格保障。
  • 具体工厂(Concrete Factory):实现抽象工厂接口,负责实例化具体的产品。作为抽象工厂的忠实拥趸,具体工厂类或是继承自抽象工厂抽象类,或是精准实现其接口。每个具体工厂类都如同一位专注的能工巧匠,与某一种特定类型的产品深度绑定,不离不弃。它负责将抽象工厂中定义的抽象创建方法生动具象化,凭借精湛技艺实实在在地生产出对应的具体产品对象,将抽象的创意构想落地生根。
  • 抽象产品(Abstract Product):定义了产品的接口,具体的产品类将实现这个接口。抽象产品恰似一份精心绘制的蓝图,多以抽象类或接口呈现。它事无巨细地概括了产品所应具备的公共方法、必备属性,为所有跃跃欲试的具体产品类精心规划了前行方向,是判断具体产品是否达标的严苛基准线。
  • 具体产品(Concrete Product):实现了抽象产品接口,是工厂模式所创建的对象。具体产品类则是依据抽象产品所勾勒的蓝图,加班加点精心打造出来的实体杰作。它们或是继承自抽象产品类,或是完美实现其接口,通过夜以继日地实现其中所定义的各种方法,赋予了产品鲜活的生命力,展现出实实在在的功能与特性,以满足千变万化的业务场景需求。

2.3、抽象工厂模式:提供了一组相关或相互依赖的对象的创建接口,而无需指定它们具体的类。这是一种更为复杂的工厂模式,通常用来创建一系列相关的对象。

三、实现步骤及代码示例

以Java为例,展示工厂模式的具体使用。

1、简单工厂模式

// 抽象产品
interface Car {void drive();
}// 具体产品
class BMW implements Car {@Overridepublic void drive() {System.out.println("Driving BMW");}
}class Benz implements Car {@Overridepublic void drive() {System.out.println("Driving Benz");}
}// 工厂类
class CarFactory {public static Car createCar(String type) {if ("BMW".equalsIgnoreCase(type)) {return new BMW();} else if ("Benz".equalsIgnoreCase(type)) {return new Benz();}return null;}
}// 客户端代码
public class Client {public static void main(String[] args) {Car car1 = CarFactory.createCar("BMW");car1.drive();Car car2 = CarFactory.createCar("Benz");car2.drive();}
}

2、工厂方法模式

// 抽象产品
interface Car {void drive();
}// 具体产品
class BMW implements Car {@Overridepublic void drive() {System.out.println("Driving BMW");}
}class Benz implements Car {@Overridepublic void drive() {System.out.println("Driving Benz");}
}// 抽象工厂
interface CarFactory {Car createCar();
}// 具体工厂
class BMWFactory implements CarFactory {@Overridepublic Car createCar() {return new BMW();}
}class BenzFactory implements CarFactory {@Overridepublic Car createCar() {return new Benz();}
}// 客户端代码
public class Client {public static void main(String[] args) {CarFactory bmwFactory = new BMWFactory();Car bmw = bmwFactory.createCar();bmw.drive();CarFactory benzFactory = new BenzFactory();Car benz = benzFactory.createCar();benz.drive();}
}

3、抽象工厂模式

由于抽象工厂模式较为复杂,此处不展开代码示例,但核心思想是提供一个接口,用于创建相关或依赖对象的家族,而不需要指明具体类。

四、常见技术框架应用

1、Spring框架

应用场景:在Spring框架中,工厂模式常用于Bean的创建和管理。Spring容器通过工厂模式来实例化和管理应用程序中的Bean,使得开发者无需手动创建和管理这些对象。

实现方式:Spring容器通过反射机制来调用具体的工厂方法或构造器,创建Bean实例。同时,Spring还支持通过配置文件或注解来指定Bean的创建方式和依赖关系。

2、MyBatis框架

应用场景:MyBatis框架中,SqlSessionFactory是创建SqlSession的工厂类。SqlSession是MyBatis的核心接口,用于执行SQL语句和管理事务。

实现方式:MyBatis通过读取配置文件或注解来构建SqlSessionFactory,然后通过SqlSessionFactory来创建SqlSession实例。这样,开发者无需直接操作数据库连接和SQL语句,提高了代码的可维护性和可扩展性。

3、Java EE/Jakarta EE

应用场景:在Java EE/Jakarta EE中,工厂模式常用于创建和管理企业级应用中的组件和服务。例如,JNDI(Java Naming and Directory Interface)服务通过工厂模式来查找和获取各种资源(如数据库连接、消息队列等)。

实现方式:Java EE/Jakarta EE提供了多种工厂类和接口来支持企业级应用的开发。开发者可以通过这些工厂类和接口来获取所需的服务和资源,而无需关心具体的实现细节。

4、日志框架(如Log4j、SLF4J)

应用场景:日志框架中,工厂模式常用于创建不同类型的日志记录器。根据不同的配置或运行时参数,可以动态地创建和使用不同的日志对象。

实现方式:日志框架通常定义了一个日志接口和多个具体的日志实现类。然后,通过工厂模式来根据配置或参数创建具体的日志记录器实例。这样,开发者可以在不修改代码的情况下灵活地切换日志实现。

5、UI框架(如Swing、JavaFX)

应用场景:在UI框架中,工厂模式常用于创建和管理用户界面组件。通过工厂模式,可以方便地创建和配置各种UI组件,如按钮、文本框、标签等。

实现方式:UI框架通常提供了一组工厂类或方法来创建和管理UI组件。开发者可以通过这些工厂类或方法来创建所需的UI组件,并设置其属性和行为。

以 Spring Boot 框架创建不同数据源连接为例

首先,定义抽象产品:

// 抽象产品:数据源连接
public interface DataSourceConnection {void connect();void close();
}

接着,创建具体产品:

// 具体产品:MySQL 数据源连接
public class MySQLDataSourceConnection implements DataSourceConnection {@Overridepublic void connect() {System.out.println("正在连接 MySQL 数据源...");// 实际连接 MySQL 数据库的代码,此处省略,如加载驱动、配置 URL、用户名、密码等}@Overridepublic void close() {System.out.println("正在关闭 MySQL 数据源连接...");// 关闭连接的代码,此处省略}
}// 具体产品:Oracle 数据源连接
public class OracleDataSourceConnection implements DataSourceConnection {@Overridepublic void connect() {System.out.println("正在连接 Oracle 数据源...");// 实际连接 Oracle 数据库的代码,此处省略,如加载驱动、配置 URL、用户名、密码等}@Overridepublic void close() {System.out.println("正在关闭 Oracle 数据源连接...");// 关闭连接的代码,此处省略}
}

然后,定义抽象工厂:

// 抽象工厂:数据源连接工厂
public abstract class DataSourceConnectionFactory {public abstract DataSourceConnection createConnection();
}

再创建具体工厂:

// 具体工厂:MySQL 数据源连接工厂
public class MySQLDataSourceConnectionFactory extends DataSourceConnectionFactory {@Overridepublic DataSourceConnection createConnection() {return new MySQLDataSourceConnection();}
}// 具体工厂:Oracle 数据源连接工厂
public class OracleDataSourceConnectionFactory extends DataSourceConnectionFactory {@Override
·public DataSourceConnection createConnection() {return new OracleDataSourceConnection();}
}

最后,在 Spring Boot 应用中使用:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class DataSourceConfig {@Beanpublic DataSourceConnectionFactory mySQLDataSourceConnectionFactory() {return new MySQLDataSourceConnectionFactory();}@Beanpublic DataSourceConnectionFactory oracleDataSourceConnectionFactory() {return new OracleDataSourceConnectionFactory();}
}

在其他业务代码中,就可以通过 @Autowired 注解注入工厂类,进而获取相应的数据源连接,例如:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class DatabaseService {@Autowiredprivate DataSourceConnectionFactory mySQLDataSourceConnectionFactory;public void doSomething() {DataSourceConnection connection = mySQLDataSourceConnectionFactory.createConnection();connection.connect();connection.close();}
}

以 Hibernate 框架为例

在 Hibernate 中,SessionFactory 可看作是抽象工厂,它负责创建 Session(相当于产品)。

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;public class HibernateExample {public static void main(String[] args) {// 创建 SessionFactory,相当于创建抽象工厂SessionFactory sessionFactory = new Configuration().buildSessionFactory();// 从工厂中获取 Session,相当于使用具体工厂创建产品Session session = sessionFactory.openSession();// 使用 Session 进行数据库操作,此处省略具体代码session.close();sessionFactory.close();}
}

这里,Configuration 类中的一些配置方法和内部逻辑就类似于具体工厂的构建过程,最终构建出 SessionFactory,而 SessionFactory 依据配置信息创建出 Session,用于后续的数据库交互操作。

五、应用场景

  1. 复杂对象创建:当对象创建涉及读取复杂配置文件获取关键初始化参数,像创建数据库连接对象时,要依据配置文件中的数据库 URL、用户名、密码精准配置,还要加载特定的数据库驱动程序,工厂模式便能大显身手,将这些复杂且易错的操作统统封装进工厂类中,使得业务代码只需关注如何使用创建好的对象,彻底与复杂的创建过程绝缘。
  2. 多类型对象按需创建:依据用户输入(如图形编辑软件根据用户所选图形类型创建圆形、矩形、三角形等不同图形)、系统状态(如电商系统根据促销活动创建不同折扣的商品对象)、业务规则(如根据不同的会员等级提供不同服务套餐)等条件,工厂模式通过巧妙设计不同的使具体工厂,能够精准无误地根据各种条件创建出对应的对象,满足多样化的业务需求,实现个性化服务。
  3. 对象创建逻辑频繁变动:在电商促销活动期间,需要根据不同的促销规则频繁创建不同折扣的商品对象;又或是在软件系统迭代升级过程中,需要不断调整对象的创建逻辑以适应新的架构要求。此时,工厂模式的优势就淋漓尽致地展现出来了,它能够在工厂类中方便地修改和扩展对象创建逻辑,而不会对使用这些对象的另业务代码造成任何影响,确保了系统的稳定性与可维护性,让代码在变革中依然保持优雅。

六、优缺点

优点

  1. 解耦对象创建与使用:清晰地划分了对象创建和使用的职责边界,极大地降低了代码之间的耦合度。使得使用对象的代码能够独立于对象的创建过程,便于后续的维护与扩展。当需要对对象创建方式进行调整时,只需在工厂类中进行改动,而不会波及到整个代码库,为代码的长期演进提供了保障。
  2. 提高代码复用性:工厂类具有很强的复用性,尤其是在对象创建过程比较复杂的情况下,复用工厂类能够避免在多个地方重复编写繁琐的创建代码。例如,多个模块都需要创建相同类型的数据库连接对象,此时只需复用同一个数据库连接工厂即可,大大提高了开发效率,减少了代码冗余。
  3. 便于代码的维护和扩展:当需要添加新的产品或者修改产品的创建逻辑时,只需要在所在的工厂类和相应的产品类中进行修改,而不会影响到其他使用这些产品的代码。例如,要在图形绘制系统中添加一种新的品类型,只需要创建新的具体产品类和对应的具体工厂类,而不需要修改图形绘制的主程序,使得系统的可扩展性得到了显著提升,能快速适应业务的变化。

优点

  1. 增加代码复杂性:引入工厂模式必然会增加代码的层次结构和类的数量。对于一些简单的应用场景,如果过度使用工厂模式,反而会使代码变得更加复杂,晦涩难懂,增加了开发人员的理解成本和维护难度。原本简单直接的创建过程可能被层层工厂类包裹,让人迷失在代码的迷宫之中。
  2. 工厂类可能会变得复杂:如果工厂需要创建的产品种类过多,或者产品的创建逻辑非常复杂,工厂类本身可能会变得庞大而复杂,不利于代码的维护。例如,一个工厂类需要根据几十种不同的条件来创建不同类型的对象,此时这个工厂类的代码将会非常冗长,难以理清其中的逻辑关系,给后续的维护工作带来巨大挑战,甚至可能成为代码维护的“黑洞”。

工厂模式凭借其独特的设计理念,为对象创建提供了一种高效、灵活且易于维护的解决方案。尽管存在一定的局限性,但在复杂多变的软件开发场景中,只要合理运用,就能充分发挥其优势,助力打造高质量的软件系统。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/502315.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Block总结】Conv2Former中的Block,卷积调制块,简化了自注意力机制,提高了内存效率

论文介绍 论文链接:https://arxiv.org/pdf/2211.11943 研究背景:论文指出,尽管当前研究者们通过利用大核卷积、高阶空间交互或稀疏卷积核等方法对卷积神经网络(ConvNets)的设计进行了重新思考,但如何更有…

w139华强北商城二手手机管理系统

🙊作者简介:多年一线开发工作经验,原创团队,分享技术代码帮助学生学习,独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取,记得注明来意哦~🌹赠送计算机毕业设计600个选题excel文…

ThreadPoolExecutor keepAliveTime 含义

现象 在线上环境排查问题时,某个线程池在某个时间点新建线程达到设定的最大线程数 maximumPoolSize,后续流量降低后当前线程数仍未回落,仍然为最大线程数,阻塞队列中有任务,但是活跃线程数显著减少。 之前的认知 固…

如何恢复已删除的 Telegram 消息 [iOSamp;Android]

Telegram 是一款功能强大的消息应用程序,因其易用性、隐私保护和众多炫酷功能而深受用户喜爱。然而,有时我们会不小心删除重要的消息。在这种情况下你应该做什么? 本文将为您提供简单有效的解决方案来恢复 Telegram 上已删除的消息&#xff…

Outlook2024版如何回到经典Outlook

Outlook2024版如何回到经典Outlook 如果新加入一家公司,拿到的电脑,大概率是最新版的Windows, 一切都是新的。 如果不coding, 使用国产的foxmail大概就可以解决一切问题了。可惜老程序员很多Coding都是基于传统Outlook的,科技公司所有人都是I…

动态库dll与静态库lib编程4:MFC规则DLL讲解

文章目录 前言一、说明二、具体实现2.1新建项目2.2 模块切换的演示 总结 前言 动态库dll与静态库lib编程4:MFC规则DLL讲解。 一、说明 1.前面介绍的均为Win32DLL,即不使用MFC的DLL。 2.MFC规则DLL的特点:DLL内部可以使用MFC类库、可以被其他…

若依中Feign调用的具体使用(若依微服务版自身已集成openfeign依赖,并在此基础上定义了自己的注解)

若依中Feign调用具体使用 注意:以下所有步骤实现的前提是需要在启动类上加入注解 EnableRyFeignClients 主要是为开启feign接口扫描 1.创建服务提供者(provider) 导入依赖(我在分析依赖时发现若依本身已经引入openfeign依赖,并在此基础上自定义了自己的EnableRyF…

CSS3——3. 书写格式二

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title></title></head><body><!--css书写&#xff1a;--><!--1. 属性名:属性值--><!--2.属性值是对属性的相关描述--><!--3.属性名必须是…

zookeeper 数据类型

文章目录 引言I Znodezonde stat (状态信息)znode类型临时\永久序列化特性引言 在结构上与标准文件系统非常类似,拥有一个层次的命名空间,都是采用树形层次结构 Zookeeper树中的每个节点被称为:Znode,没有文件和目录之分。Znode兼具文件和目录两种特点Znode存储数据大小有…

Hadoop集群之间实现免密登录

实现虚拟机之间能够互相登录&#xff0c;比如可以在hadoop1上面登录hadoop2。 第一步&#xff1a;执行”ssh-keygen -t rsa”命令&#xff0c;生成该虚拟机的密钥 第二步&#xff1a;密钥文件存储在/root/.ssh目录&#xff0c;执行cd /root/.ssh命令进入存储密钥文件的目录&am…

【linux基础I/O(1)】文件描述符的本质重定向的本质

目录 前言1. 理解C语言的文件接口2. 操作文件的系统调用接口2.1 open函数详解2.2 close函数详解2.3 write函数详解2.4 read函数详解 3. 文件描述符fd详解4. 文件描述符的内核本质5. 怎样理解Linux下一切皆文件?6. 理解输出输入重定向7. 重定向的系统调用8. 总结 前言 “在Lin…

C++:范围for

范围for&#xff08;range-based for&#xff09;是C的一种循环结构&#xff0c; 是在 C11 这个标准中引入的&#xff0c;这种类型的for循环使得遍历数组、容器中的元素更加简便和直观。 一、范围for语法 for ( 类型 变量名 : 数组名 ) 语句 //多条语句需要加⼤括号 示例&#…

C语言 递归编程练习

1.将参数字符串中的字符反向排列&#xff0c;不是逆序打印。 要求&#xff1a;不能使用C函数库中的字符串操作函数。 比如&#xff1a; char arr[] "abcdef"; 逆序之后数组的内容变成&#xff1a;fedcba 1.非函数实现&#xff08;循环&#xff09; 2.用递归方法…

Spring Boot - 日志功能深度解析与实践指南

文章目录 概述1. Spring Boot 日志功能概述2. 默认日志框架&#xff1a;LogbackLogback 的核心组件Logback 的配置文件 3. 日志级别及其配置配置日志级别3.1 配置文件3.2 环境变量3.3 命令行参数 4. 日志格式自定义自定义日志格式 5. 日志文件输出6. 日志归档与清理7. 自定义日…

USB子系统学习(一)USB电气信号

文章目录 1、声明2、USB协议概述3、USB电气信号3.1、USB基础概念3.1.1、低速/全速信号电平3.1.2、高速信号电平 3.2、学习目标3.3、设备断开与连接3.3.1、连接3.3.2、断开 3.4、复位3.5、设备速率识别3.5.1、低速/全速3.5.2、高速 3.6、数据信号3.6.1、低速/全速的SOP和EOP3.6.…

Android GameActivity(NativeActivity)读写文件

最近研究native android相关内容&#xff0c;其中最棘手的就是文件读写问题&#xff0c;最主要的是相关的文档很少。这里写下我所知道的方法。 由于本人使用的是Android14[arm64-v8a]版本的设备,能访问的路径相当有限&#xff0c;如果想要访问更多的路径&#xff0c;就不得不申…

安卓入门十一 常用网络协议四

MQTT&#xff08;Message Queuing Telemetry Transport&#xff09; MQTT是一种轻量级的、发布/订阅模式的消息传输协议。它被设计用于在低带宽或不稳定网络环境下&#xff0c;实现物联网设备之间的可靠通信。 4.1 MQTT详细介绍 发布/订阅模式&#xff1a;MQTT 使用发布/订…

气膜球幕:引领元宇宙时代的科技与艺术光影盛宴—轻空间

在科技与艺术交织的时代&#xff0c;未来的观影体验将不再受限于传统屏幕的束缚。随着气膜球幕的崭新亮相&#xff0c;突破性的光影效果和沉浸式体验让我们走进了一个全新的视听世界。这不仅仅是一个简单的球形影院&#xff0c;它是连接现实与虚拟、科技与艺术、光与影的桥梁&a…

Hyperbolic dynamics

http://www.scholarpedia.org/article/Hyperbolic_dynamics#:~:textAmong%20smooth%20dynamical%20systems%2C%20hyperbolic%20dynamics%20is%20characterized,semilocal%20or%20even%20global%20information%20about%20the%20dynamics. 什么是双曲动力系统&#xff1f; A hy…

kernel32.dll动态链接库报错要怎解决?详细解析kernel32.dll文件缺失解决方案

Kernel32.dll动态链接库报错详解与解决方案 在电脑的日常使用中&#xff0c;我们时常会遇到各种系统报错&#xff0c;其中kernel32.dll文件的报错尤为让人头疼。作为一名在软件开发领域摸爬滚打多年的从业者&#xff0c;我将为大家深入解析kernel32.dll文件的重要性&#xff0…