工厂模式:对象创建的智慧之道

引言:为什么我们需要工厂模式?

在软件开发中,对象创建是最常见的操作之一。当代码中充满new关键字时,系统会面临三大痛点:

  1. 紧耦合:客户端代码直接依赖具体实现类
  2. 扩展困难:新增产品类型需修改多处代码
  3. 职责混乱:业务逻辑与对象创建逻辑混杂

工厂模式(Factory Pattern)正是解决这些问题的创建型设计模式。它通过定义对象创建接口,让子类决定实例化哪个类,实现创建逻辑与使用逻辑的解耦

工厂模式家族包含三种形态:简单工厂工厂方法抽象工厂,各自解决不同层次的问题。


一、简单工厂模式(静态工厂)

1.1 基础概念

classDiagramclass Clientclass SimpleFactory {+createProduct(String type) Product}interface Product {+use()}class ConcreteProductAclass ConcreteProductBClient --> SimpleFactorySimpleFactory ..> ProductProduct <|.. ConcreteProductAProduct <|.. ConcreteProductB

1.2 代码实现

// 产品接口
interface Button {void render();
}// 具体产品
class WindowsButton implements Button {public void render() {System.out.println("渲染Windows风格按钮");}
}class MacOSButton implements Button {public void render() {System.out.println("渲染MacOS风格按钮");}
}// 简单工厂
class ButtonFactory {public static Button createButton(String osType) {if ("windows".equalsIgnoreCase(osType)) {return new WindowsButton();} else if ("macos".equalsIgnoreCase(osType)) {return new MacOSButton();}throw new IllegalArgumentException("未知操作系统类型");}
}// 客户端调用
public class Client {public static void main(String[] args) {Button btn = ButtonFactory.createButton("macos");btn.render(); // 输出:渲染MacOS风格按钮}
}

1.3 适用场景与局限

适用场景

  • 产品种类有限且固定
  • 客户端不关心创建细节

缺点

  • 违反开闭原则(新增产品需修改工厂)
  • 工厂类职责过重

二、工厂方法模式(多态工厂)

2.1 核心思想

classDiagramclass Clientinterface Factory {+createButton() Button}class WindowsFactoryclass MacOSFactoryinterface Buttonclass WindowsButtonclass MacOSButtonClient --> FactoryFactory <|.. WindowsFactoryFactory <|.. MacOSFactoryFactory ..> ButtonButton <|.. WindowsButtonButton <|.. MacOSButton

2.2 代码实现

// 抽象工厂
interface GUIFactory {Button createButton();Checkbox createCheckbox();
}// 具体工厂
class WindowsFactory implements GUIFactory {public Button createButton() {return new WindowsButton();}public Checkbox createCheckbox() {return new WindowsCheckbox();}
}class MacOSFactory implements GUIFactory {public Button createButton() {return new MacOSButton();}public Checkbox createCheckbox() {return new MacOSCheckbox();}
}// 客户端代码
public class Application {private Button button;private Checkbox checkbox;public Application(GUIFactory factory) {button = factory.createButton();checkbox = factory.createCheckbox();}public void render() {button.render();checkbox.render();}
}// 使用示例
public class Demo {public static void main(String[] args) {GUIFactory factory;if (System.getProperty("os.name").contains("Windows")) {factory = new WindowsFactory();} else {factory = new MacOSFactory();}Application app = new Application(factory);app.render();}
}

2.3 模式优势

  1. 完全符合开闭原则:新增产品只需添加新工厂
  2. 单一职责原则:每个工厂只负责一类产品
  3. 可测试性:可通过Mock工厂进行单元测试

三、抽象工厂模式(产品族工厂)

3.1 解决复杂产品族创建

classDiagramclass Clientinterface AbstractFactory {+createButton() Button+createCheckbox() Checkbox}class ModernFactoryclass VintageFactoryinterface Buttoninterface Checkboxclass ModernButtonclass VintageButtonclass ModernCheckboxclass VintageCheckboxClient --> AbstractFactoryAbstractFactory <|.. ModernFactoryAbstractFactory <|.. VintageFactoryAbstractFactory ..> ButtonAbstractFactory ..> CheckboxButton <|.. ModernButtonButton <|.. VintageButtonCheckbox <|.. ModernCheckboxCheckbox <|.. VintageCheckbox

3.2 跨平台UI案例

// 抽象产品族
interface Button {void render();
}interface Checkbox {void toggle();
}// 现代风格产品
class ModernButton implements Button {public void render() {System.out.println("渲染扁平化按钮");}
}class ModernCheckbox implements Checkbox {public void toggle() {System.out.println("切换Material Design复选框");}
}// 复古风格产品
class VintageButton implements Button {public void render() {System.out.println("渲染拟物化按钮");}
}class VintageCheckbox implements Checkbox {public void toggle() {System.out.println("切换复古风格复选框");}
}// 抽象工厂
interface UIFactory {Button createButton();Checkbox createCheckbox();
}// 具体工厂
class ModernUIFactory implements UIFactory {public Button createButton() {return new ModernButton();}public Checkbox createCheckbox() {return new ModernCheckbox();}
}class VintageUIFactory implements UIFactory {public Button createButton() {return new VintageButton();}public Checkbox createCheckbox() {return new VintageCheckbox();}
}// 配置类(决定使用哪种风格)
class UIStyleConfig {public static UIFactory getFactory(String style) {if ("modern".equals(style)) {return new ModernUIFactory();} else if ("vintage".equals(style)) {return new VintageUIFactory();}throw new IllegalArgumentException("未知UI风格");}
}

3.3 模式特点

优势

  • 保证产品族兼容性(如统一风格的UI组件)
  • 切换产品族只需替换工厂实例

局限性

  • 新增产品类型需修改所有工厂接口
  • 类数量指数级增长(产品族×产品类型)

四、三大工厂模式对比

特性简单工厂工厂方法抽象工厂
创建对象范围单一产品单一产品产品族
开闭原则支持❌ 修改工厂类✅ 扩展新工厂✅ 扩展新工厂
复杂度★☆☆ 简单★★☆ 中等★★★ 复杂
适用场景固定类型产品单一类型产品扩展相关产品组成的家族
系统扩展方向垂直扩展(修改代码)水平扩展(新增工厂)水平扩展(新增产品族)

五、工厂模式在框架中的实践

5.1 JDK中的工厂模式

// 工厂方法示例
Calendar cal = Calendar.getInstance(); // 根据时区创建实例// 抽象工厂示例
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();

5.2 Spring框架的工厂应用

// BeanFactory:顶级工厂接口
BeanFactory factory = new ClassPathXmlApplicationContext("beans.xml");
MyService service = factory.getBean(MyService.class);// FactoryBean:定制复杂对象创建
public class MyFactoryBean implements FactoryBean<Connection> {public Connection getObject() {return DriverManager.getConnection(...);}
}

5.3 Log4j2的日志工厂

Logger logger = LogManager.getLogger(); // 获取日志器工厂

六、工厂模式最佳实践

6.1 何时使用工厂模式?

  1. 系统需要支持多种实现变体(如不同数据库驱动)
  2. 需要隔离创建逻辑与业务代码
  3. 需要统一管理对象生命周期
  4. 实现可插拔架构(运行时切换实现)

6.2 设计原则落地

  • 开闭原则:通过扩展而非修改增加功能
  • 依赖倒置:依赖抽象而非具体实现
  • 单一职责:创建逻辑与业务逻辑分离

6.3 避免常见误区

  1. 过度设计:简单场景直接使用new
  2. 工厂膨胀:当产品类型过多时考虑重构
  3. 循环依赖:工厂之间避免相互调用

七、工厂模式演进与变种

7.1 静态工厂方法

// JDK中的经典案例
List<String> list = Collections.unmodifiableList(originalList);

7.2 参数化工厂

class VehicleFactory {Vehicle createVehicle(VehicleType type, String model) {switch(type) {case CAR: return new Car(model);case TRUCK: return new Truck(model);}}
}

7.3 延迟初始化工厂

class LazyFactory {private Map<String, Product> cache = new HashMap<>();Product getProduct(String key) {if (!cache.containsKey(key)) {cache.put(key, createProduct(key));}return cache.get(key);}
}

八、工厂模式经典面试题

Q1:工厂方法和抽象工厂的核心区别?

答案

  • 工厂方法关注单一产品的创建
  • 抽象工厂关注相关产品族的创建
  • 抽象工厂通常包含多个工厂方法

Q2:Spring中的BeanFactory和FactoryBean有何不同?

答案

BeanFactoryFactoryBean
基础IoC容器创建复杂对象的工厂接口
管理所有Bean的生命周期定制特殊Bean的创建过程
通过getBean()获取对象实现getObject()返回目标对象

结语:工厂模式的价值思考

工厂模式不仅是技术实现,更是架构思维的体现。它教会我们:

  1. 解耦的艺术:分离变与不变的部分
  2. 扩展的智慧:通过组合而非修改扩展系统
  3. 抽象的边界:合理划分职责边界

在微服务和云原生时代,工厂模式演变为:

  • 依赖注入:更高级的对象装配方式
  • 服务工厂:动态服务实例创建(如gRPC)
  • 云资源工厂:按需创建云资源(AWS/Aliyun SDK)

最后提醒: 不要为了模式而模式!当创建逻辑确实存在变体时,再引入工厂模式。

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

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

相关文章

Docker镜像制作案例

1、使用Docker commit制作镜像为ubuntu镜像提供ssh服务①&#xff1a;拉取镜像[rootopenEuler-1 ~]# docker pull ubuntu:18.04②&#xff1a;启动镜像[rootopenEuler-1 ~]# docker run --name c1 -it --rm ubuntu:18.04 bash③&#xff1a;替换aliyun源mv /etc/apt/sources.li…

KeilMDK5如何生成.bin文件

1&#xff1a;主要是要找到fromelf.exe的路径2&#xff1a;接下来要做的要视情况而定&#xff1a;选完fromelf.exe后在输入框中加个空格然后加一串字 : --bin -o ./Obj/L.bin ./Obj/L.axf&#xff0c;如下我设置的L最终会替换成项目名 3&#xff1a;去构建生成编译一下&#…

Ajax接收java后端传递的json对象包含长整型被截断导致丢失精度的解决方案

问题描述 在使用java编写代码的时候,后端返回前端的JSON对象中包含了Long长整型,前端接受的时候丢失了精度问题。 比如: 后端传递的json {"code": "200","msg": "操作成功","data":

MybatisPlus由浅入深

MyBatis-Plus&#xff08;简称 MP&#xff09;是一个 MyBatis 的增强工具&#xff0c;旨在简化开发过程。基本使用步骤1.依赖引入<!-- mysql依赖 --> <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId>…

蓝牙信号强度(RSSI)与链路质量(LQI)的测量与应用:面试高频考点与真题解析

在蓝牙通信领域&#xff0c;信号强度&#xff08;RSSI&#xff09;和链路质量&#xff08;LQI&#xff09;是评估无线链路性能的核心指标。无论是智能家居设备的连接优化&#xff0c;还是工业物联网中的抗干扰设计&#xff0c;这两个指标都扮演着关键角色。本文将结合面试高频考…

PyTorch的计算图是什么?为什么绘图前要detach?

在PyTorch中&#xff0c;计算图&#xff08;Computational Graph&#xff09; 是自动求导&#xff08;Autograd&#xff09;的核心机制。理解计算图有助于解释为什么在绘图前需要使用 .detach() 方法分离张量。一、什么是计算图&#xff1f; 计算图是一种有向无环图&#xff08…

深度学习入门代码详细注释-ResNet18分类蚂蚁蜜蜂

本项目将基于PyTorch平台迁移ResNet18模型。该模型原采用ImageNet数据集&#xff08;含1000个图像类别&#xff09;进行训练。我们将尝试运用该模型对蚂蚁和蜜蜂进行分类&#xff08;这两个类别未包含在原训练数据集中&#xff09;。 本文的原始代码参考于博客深度学习入门项目…

北京饮马河科技公司 Java 实习面经

北京饮马河科技公司 Java 实习面经 本文作者&#xff1a;程序员小白条 本站地址&#xff1a;https://xbt.xiaobaitiao.top 1&#xff09; 面试官&#xff1a;我看你这块是有一个开源的项目&#xff0c;这个项目主要是做什么的&#xff1f; 我&#xff1a;主要两点是亮点&…

java基础(day07)

目录 OOP编程 方法 方法的调用&#xff1a; 在main入口函数中调用&#xff1a; 动态参数&#xff1a; 方法重载 OOP编程 方法 概念&#xff1a;指为获得某种东西或达到某种目的而采取的手段与行为方式。有时候被称作“方法”&#xff0c;有时候被称作“函数”。例如UUID.…

使用EasyExcel动态合并单元格(模板方法)

1、导入EasyExcel依赖<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>4.0.3</version> </dependency>2、编写实体类Data publci class Student{ ExcelProperty("姓名")pri…

jenkins 流水线比较简单直观的

//全篇没用自定义变量pipeline {agent any// 使用工具自动配置Node.js环境tools {nodejs nodejs22 // 需在Jenkins全局工具中预配置该名称的Node.js安装}//下面拉取代码通过的是流水线片段生成的stages {stage(Checkout Code) {steps {git branch: release-v1.2.6,credentials…

CV目标检测中的LetterBox操作

LetterBox类比理解&#xff1a;想象你要把一张任意形状的照片放进一个正方形的相框里&#xff0c;照片不能变形拉伸&#xff0c;所以你先等比例缩小照片&#xff0c;然后在空余的地方填上灰色背景。第1章 数学原理当我们有一个原始图像的尺寸为 19201080&#xff08;宽高&#…

Leetcode 3614. Process String with Special Operations II

Leetcode 3614. Process String with Special Operations II 1. 解题思路2. 代码实现 题目链接&#xff1a;3614. Process String with Special Operations II 1. 解题思路 这一题思路上是一个逆推的思路。 首先&#xff0c;我们顺序走一轮不难得到最终我们能够获得的字符串…

.NET ExpandoObject 技术原理解析

&#x1f31f; .NET ExpandoObject 技术原理解析 引用&#xff1a; .NET 剖析4.0上ExpandoObject动态扩展对象原理风潇潇人渺渺快意刀山中草 #mermaid-svg-RtpHctpdchPPN1Xo {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mer…

放苹果(信息学奥赛一本通-T1192)

【题目描述】把M个同样的苹果放在N个同样的盘子里&#xff0c;允许有的盘子空着不放&#xff0c;问共有多少种不同的分法&#xff1f;&#xff08;用K表示&#xff09;5&#xff0c;1&#xff0c;1和1&#xff0c;5&#xff0c;1 是同一种分法。【输入】第一行是测试数据的数目…

(懒人救星版)CNN_Kriging_NSGA2_Topsis(多模型融合典范)深度学习+SCI热点模型+多目标+熵权法 全网首例,完全原创,早用早发SCI

全网首例&#xff0c;完全原创&#xff0c;早用早发SCI&#xff08;多模型融合典范&#xff09;机器学习SCI热点模型多目标熵权法(懒人救星版)BP_Kriging_NSGA2_Topsis 改进克里金工作量大&#xff1a;多模型融合创新性&#xff1a;首次结合BP神经网络和克里金多目标利用 BP神…

LeetCode热题100【第一天】

第一题 两数之和 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案&#xff0c;并且你不能使用两次相同的元素。 你可以按任意顺序返回…

AI Linux 运维笔记

运维基本概念 IT运维是指通过专业技术手段&#xff0c;确保企业的IT系统和网络持续、安全、稳定运行&#xff0c;保障业务的连续性。运维涵盖计算机网络、应用系统、硬件环境和服务流程的综合管理。主要分为: 系统运维、数据库运维、自动化运维、容器运维、云计算运维、信创运维…

Redis性能基准测试

基准环境 机器&#xff1a;AWS EC2 c4.8xlarge&#xff08;同机部署 Redis Server 与 ReJSONBenchmark 工具&#xff0c;通过网络栈连接&#xff09;测试工具&#xff1a;ReJSONBenchmark&#xff08;Go 实现、可配置并发&#xff09;模式&#xff1a;非管线&#xff08;non-pi…

XML外部实体注入与修复方案

XML外部实体注入&#xff08;XXE&#xff09;是一种严重的安全漏洞&#xff0c;攻击者利用XML解析器处理外部实体的功能来读取服务器内部文件、执行远程请求&#xff08;SSRF&#xff09;、扫描内网端口或发起拒绝服务攻击。以下是详细解释和修复方案&#xff1a;XXE 攻击原理外…