从模式到架构:Java 工厂模式的设计哲学与工程化实践

article/2025/8/4 5:40:50

一、工厂模式概述

(一)定义与核心思想

工厂模式(Factory Pattern)是软件开发中常用的创建型设计模式,其核心思想是将对象的创建过程封装起来,通过工厂类来统一管理对象的创建逻辑。这种模式分离了对象的创建和使用,使得客户端代码无需关心具体的创建细节,只需通过工厂获取所需对象即可。在 Java 开发中,工厂模式通过接口或抽象类定义产品和工厂的规范,具体实现类负责创建具体的产品实例,从而实现了代码的松耦合和高扩展性。

(二)核心作用与优势

  1. 解耦对象创建与使用:客户端代码与具体的对象创建逻辑分离,只需依赖工厂接口或抽象类,降低了模块间的耦合度。
  2. 符合开闭原则:当需要新增产品类型时,只需添加新的具体产品类和对应的工厂类,无需修改现有代码,提高了系统的可扩展性。
  3. 统一管理创建逻辑:将复杂的对象创建过程集中在工厂类中处理,避免了重复代码,便于维护和修改。
  4. 隐藏具体实现细节:客户端只需要知道产品的抽象接口,无需了解具体实现类的细节,增强了代码的封装性。

(三)核心角色

  1. 抽象产品(Product):定义了产品的公共接口或抽象类,所有具体产品都需要实现该接口或继承该抽象类。
  2. 具体产品(Concrete Product):实现了抽象产品接口,是具体的产品实现类。
  3. 抽象工厂(Factory):定义了创建产品的接口,通常是一个接口或抽象类。
  4. 具体工厂(Concrete Factory):实现了抽象工厂接口,负责创建具体的产品实例。

二、简单工厂模式(Simple Factory Pattern)

(一)模式定义与特点

简单工厂模式又称为静态工厂模式,它不属于 23 种经典设计模式之一,但却是工厂模式中最基础的实现方式。简单工厂模式通过一个工厂类来根据传入的参数动态决定创建哪种具体产品实例。其特点是工厂类中包含了必要的逻辑判断,能够根据客户端的需求返回对应的产品实例,但缺点是当新增产品类型时,需要修改工厂类的代码,违反了开闭原则。

(二)结构与实现步骤

1. 结构示意图

plaintext

客户端↓├─ 调用工厂类的静态方法↓
简单工厂类(SimpleFactory)↓├─ 根据参数创建具体产品实例↓
抽象产品(Product)↓
具体产品A(ConcreteProductA)、具体产品B(ConcreteProductB)
2. 实现步骤

(1)定义抽象产品接口或抽象类,声明产品的公共方法。
(2)创建具体产品类,实现抽象产品接口。
(3)设计简单工厂类,提供静态方法,根据传入的参数返回对应的具体产品实例。

(三)代码示例

1. 抽象产品接口

java

public interface Product {void display();
}
2. 具体产品类

java

public class ConcreteProductA implements Product {@Overridepublic void display() {System.out.println("这是产品A");}
}public class ConcreteProductB implements Product {@Overridepublic void display() {System.out.println("这是产品B");}
}
3. 简单工厂类

java

public class SimpleFactory {public static Product createProduct(String productType) {if ("A".equals(productType)) {return new ConcreteProductA();} else if ("B".equals(productType)) {return new ConcreteProductB();} else {throw new IllegalArgumentException("无效的产品类型");}}
}
4. 客户端调用

java

public class Client {public static void main(String[] args) {Product productA = SimpleFactory.createProduct("A");productA.display(); // 输出:这是产品AProduct productB = SimpleFactory.createProduct("B");productB.display(); // 输出:这是产品B}
}

(四)优缺点与适用场景

1. 优点
  • 实现简单,客户端无需知道具体产品的创建细节。
  • 集中管理对象的创建逻辑,便于维护。
2. 缺点
  • 工厂类职责过重,违反了单一职责原则。
  • 新增产品类型时需要修改工厂类代码,违反开闭原则。
3. 适用场景
  • 产品类型较少,且后续扩展需求不大的场景。
  • 简单的业务逻辑中,需要将对象创建逻辑集中管理的情况。

三、工厂方法模式(Factory Method Pattern)

(一)模式定义与核心思想

工厂方法模式是 23 种经典设计模式之一,它定义了一个创建产品对象的接口,但由具体工厂类决定创建哪种具体产品实例。工厂方法模式将简单工厂模式中集中的创建逻辑分散到各个具体工厂类中,每个具体工厂类负责创建一种具体产品,从而克服了简单工厂模式违反开闭原则的缺点。

(二)结构与实现步骤

1. 结构示意图

plaintext

客户端↓├─ 调用抽象工厂接口↓
抽象工厂(Factory)↓├─ 声明创建产品的抽象方法↓
具体工厂A(ConcreteFactoryA)、具体工厂B(ConcreteFactoryB)↓├─ 实现创建具体产品的方法↓
抽象产品(Product)↓
具体产品A(ConcreteProductA)、具体产品B(ConcreteProductB)
2. 实现步骤

(1)定义抽象产品接口,声明产品的公共方法。
(2)创建具体产品类,实现抽象产品接口。
(3)定义抽象工厂接口,声明创建产品的抽象方法。
(4)创建具体工厂类,实现抽象工厂接口,具体工厂类负责创建对应的具体产品实例。

(三)代码示例

1. 抽象产品接口(同简单工厂模式)

java

public interface Product {void display();
}
2. 具体产品类(同简单工厂模式)

java

public class ConcreteProductA implements Product {@Overridepublic void display() {System.out.println("这是产品A");}
}public class ConcreteProductB implements Product {@Overridepublic void display() {System.out.println("这是产品B");}
}
3. 抽象工厂接口

java

public interface Factory {Product createProduct();
}
4. 具体工厂类

java

public class ConcreteFactoryA implements Factory {@Overridepublic Product createProduct() {return new ConcreteProductA();}
}public class ConcreteFactoryB implements Factory {@Overridepublic Product createProduct() {return new ConcreteProductB();}
}
5. 客户端调用

java

public class Client {public static void main(String[] args) {Factory factoryA = new ConcreteFactoryA();Product productA = factoryA.createProduct();productA.display(); // 输出:这是产品AFactory factoryB = new ConcreteFactoryB();Product productB = factoryB.createProduct();productB.display(); // 输出:这是产品B}
}

(四)优缺点与适用场景

1. 优点
  • 符合开闭原则,新增产品类型时只需添加新的具体产品类和具体工厂类,无需修改现有代码。
  • 每个具体工厂类负责创建一种产品,符合单一职责原则。
  • 客户端只依赖抽象接口,降低了与具体实现类的耦合度。
2. 缺点
  • 当产品类型较多时,会导致具体工厂类的数量增加,系统复杂度上升。
  • 对于简单的对象创建场景,可能会引入过多的类,增加代码的复杂性。
3. 适用场景
  • 当系统需要灵活地创建不同类型的产品,且新增产品类型频繁时。
  • 希望将对象的创建逻辑与使用逻辑分离,提高代码的可扩展性和维护性。
  • 客户端只需要知道产品的抽象接口,不需要了解具体实现类的情况。

四、抽象工厂模式(Abstract Factory Pattern)

(一)模式定义与核心思想

抽象工厂模式是工厂方法模式的扩展,它提供了一种创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。抽象工厂模式用于创建属于不同产品族的产品对象,每个产品族中的产品具有某种共同的特性或功能,例如不同操作系统下的界面组件(Windows 和 Linux 下的按钮、文本框等)。

(二)核心概念

  1. 产品族:指位于不同产品等级结构中,功能相关联的产品组成的家族。例如,Windows 系统下的按钮、文本框属于一个产品族,Linux 系统下的按钮、文本框属于另一个产品族。
  2. 产品等级结构:指产品的继承结构,例如按钮作为一个抽象产品,有 Windows 按钮和 Linux 按钮两个具体产品,形成一个产品等级结构。

(三)结构与实现步骤

1. 结构示意图

plaintext

客户端↓├─ 调用抽象工厂接口创建产品族↓
抽象工厂(AbstractFactory)↓├─ 声明创建各产品等级结构中产品的方法↓
具体工厂A(ConcreteFactoryA)、具体工厂B(ConcreteFactoryB)↓├─ 实现创建具体产品族的方法↓
抽象产品A(AbstractProductA)、抽象产品B(AbstractProductB)↓
具体产品A1(ConcreteProductA1)、具体产品A2(ConcreteProductA2)
具体产品B1(ConcreteProductB1)、具体产品B2(ConcreteProductB2)
2. 实现步骤

(1)定义多个抽象产品接口,分别代表不同的产品等级结构。
(2)创建具体产品类,实现对应的抽象产品接口。
(3)定义抽象工厂接口,声明创建各个抽象产品的方法。
(4)创建具体工厂类,实现抽象工厂接口,具体工厂类负责创建属于同一产品族的多个产品实例。

(四)代码示例

1. 抽象产品接口(产品等级结构 1:按钮)

java

public interface Button {void display();
}public class WindowsButton implements Button {@Overridepublic void display() {System.out.println("Windows按钮");}
}public class LinuxButton implements Button {@Overridepublic void display() {System.out.println("Linux按钮");}
}
2. 抽象产品接口(产品等级结构 2:文本框)

java

public interface TextBox {void display();
}public class WindowsTextBox implements TextBox {@Overridepublic void display() {System.out.println("Windows文本框");}
}public class LinuxTextBox implements TextBox {@Overridepublic void display() {System.out.println("Linux文本框");}
}
3. 抽象工厂接口

java

public interface GUIFactory {Button createButton();TextBox createTextBox();
}
4. 具体工厂类(Windows 工厂)

java

public class WindowsFactory implements GUIFactory {@Overridepublic Button createButton() {return new WindowsButton();}@Overridepublic TextBox createTextBox() {return new WindowsTextBox();}
}
5. 具体工厂类(Linux 工厂)

java

public class LinuxFactory implements GUIFactory {@Overridepublic Button createButton() {return new LinuxButton();}@Overridepublic TextBox createTextBox() {return new LinuxTextBox();}
}
6. 客户端调用

java

public class Client {public static void main(String[] args) {GUIFactory factory = new WindowsFactory();Button button = factory.createButton();TextBox textBox = factory.createTextBox();button.display(); // 输出:Windows按钮textBox.display(); // 输出:Windows文本框factory = new LinuxFactory();button = factory.createButton();textBox = factory.createTextBox();button.display(); // 输出:Linux按钮textBox.display(); // 输出:Linux文本框}
}

(五)优缺点与适用场景

1. 优点
  • 可以创建多个产品族的产品,满足复杂的对象创建需求。
  • 客户端只依赖抽象接口,无需了解具体产品的创建细节,提高了代码的可维护性和扩展性。
  • 确保同一产品族中的产品之间的兼容性,例如 Windows 工厂创建的按钮和文本框一定是相互兼容的。
2. 缺点
  • 当需要新增一个产品等级结构时,需要修改抽象工厂接口和所有具体工厂类,违反了开闭原则。
  • 系统复杂度较高,适用于产品族较多且稳定的场景。
3. 适用场景
  • 系统需要创建多个相关或相互依赖的对象族,例如不同操作系统下的界面组件。
  • 产品族中的产品种类固定,且不会频繁新增产品等级结构的场景。
  • 需要确保产品族中的产品之间相互兼容,避免客户端直接创建具体产品类的情况。

五、三种工厂模式的对比与选择

(一)模式对比表

特征简单工厂模式工厂方法模式抽象工厂模式
工厂类数量一个工厂类多个具体工厂类多个具体工厂类
产品等级结构单个产品等级结构单个产品等级结构多个产品等级结构
产品族不支持不支持支持
开闭原则违反符合部分符合(新增产品族符合,新增产品等级结构违反)
复杂度简单中等复杂

(二)选择策略

  1. 简单工厂模式:适用于产品类型较少、逻辑简单且后续扩展需求不大的场景,可快速实现对象的集中创建。
  2. 工厂方法模式:当系统需要灵活地新增产品类型,且每个产品类型的创建逻辑相对独立时,优先选择工厂方法模式,它符合开闭原则,易于扩展。
  3. 抽象工厂模式:当系统需要处理多个产品族,且每个产品族包含多个相关产品时,抽象工厂模式能够高效地管理产品族的创建,确保产品之间的兼容性。

六、工厂模式与设计原则

(一)开闭原则

工厂模式通过抽象接口和具体实现的分离,使得新增产品类型或产品族时无需修改现有代码,只需添加新的具体类,符合开闭原则的 “对扩展开放,对修改关闭” 要求。

(二)单一职责原则

工厂方法模式和抽象工厂模式中,每个具体工厂类只负责创建一种或一类产品,符合单一职责原则,而简单工厂模式的工厂类职责较为集中,可能违反该原则。

(三)依赖倒置原则

工厂模式中,客户端依赖抽象产品接口和抽象工厂接口,而不是具体实现类,遵循了依赖倒置原则,降低了客户端与具体实现的耦合度。

(四)里氏替换原则

具体产品类必须实现抽象产品接口的所有方法,具体工厂类必须实现抽象工厂接口的所有方法,确保了子类可以无缝替换父类,符合里氏替换原则。

七、工厂模式在 Java 中的应用场景

(一)Java 集合框架

在 Java 集合框架中,Collection接口是抽象产品,ArrayListLinkedList等是具体产品,而它们的创建过程虽然没有显式的工厂类,但通过构造方法或工厂方法(如Arrays.asList())实现了对象的创建,体现了工厂模式的思想。

(二)Spring 框架

Spring 框架中的 BeanFactory 和 ApplicationContext 就是工厂模式的典型应用。BeanFactory 作为抽象工厂,负责创建各种 Bean 对象,而具体的 Bean 创建逻辑由具体的工厂类(如 DefaultListableBeanFactory)实现。通过配置文件或注解,客户端可以轻松获取所需的 Bean 实例,无需关心对象的创建细节。

(三)JDBC 驱动

JDBC 中使用DriverManager获取数据库连接的过程也应用了工厂模式。DriverManager作为工厂类,根据不同的数据库 URL 创建对应的数据库连接(Connection对象),客户端只需通过统一的接口操作数据库,无需了解具体数据库驱动的创建细节。

八、总结与最佳实践

(一)模式价值

工厂模式是面向对象设计中处理对象创建的重要模式,它通过封装对象创建逻辑,提高了代码的可维护性、可扩展性和可复用性。无论是简单工厂模式的快速实现,还是工厂方法模式和抽象工厂模式的灵活扩展,都为软件开发提供了有效的解决方案。

(二)最佳实践

  1. 优先使用组合而非继承:在设计工厂类时,尽量通过组合的方式复用创建逻辑,避免过度使用继承导致系统复杂度增加。
  2. 明确抽象层次:合理定义抽象产品接口和抽象工厂接口,确保接口的稳定性和扩展性,避免频繁修改接口。
  3. 结合其他模式:工厂模式可以与单例模式、原型模式等结合使用,例如将工厂类设计为单例,确保全局唯一的创建点。
  4. 测试工厂逻辑:由于工厂类负责对象的创建,需要对其进行充分的测试,确保返回的产品实例符合预期,尤其是在处理复杂创建逻辑时。

(三)未来趋势

随着软件开发的复杂化和模块化需求的增加,工厂模式在微服务、框架设计等领域的应用将更加广泛。结合 Java 8 的函数式接口和 Lambda 表达式,工厂模式的实现方式也在不断演进,例如使用Supplier接口简化对象创建过程,提高代码的简洁性和灵活性。

总之,掌握工厂模式的核心思想和不同实现方式,能够帮助开发者在实际项目中更好地设计对象创建逻辑,提升系统的可维护性和扩展性,是 Java 开发中不可或缺的重要设计模式之一。


http://www.hkcw.cn/article/OeLBtGVKdT.shtml

相关文章

Torch 和 CUDA 版本不兼容

原因解释 参考:https://stackoverflow.com/questions/76678846/pytorch-version-for-cuda-12-2 nvcc CUDA Toolkit 12.6 Downloads | NVIDIA Developer nvcc: NVIDIA (R) Cuda compiler driver Copyright (c) 2005-2024 NVIDIA Corporation Built on Fri_Jun_14_…

第九天:java注解

注解 1 什么是注解(Annotation) public class Test01 extends Object{//Override重写的注解Overridepublic String toString() {return "Test01{}";} }2 内置注解 2.1 Override Override重写的注解 Override public String toString() {ret…

Linux --进程状态

目录 进程状态(宏观) Linux进程状态 进程状态的查看 进程状态(宏观) 为了了解Linux的进程状态,首先我们得了解进程状态,因为不仅仅是在Linux下有进程状态,macos和windows下都有进程状态,这里先解释的是一个宏观概念下的&#xff…

定时任务:springboot集成xxl-job-core(二)

定时任务实现方式: 存在的问题: xxl-job的原理: 可以根据服务器的个数进行动态分片,每台服务器分到的处理数据是不一样的。 1. 多台机器动态注册 多台机器同时配置了调度器xxl-job-admin之后,执行器那里会有多个注…

操作系统学习(十)——文件系统

一、文件系统 在操作系统中,文件系统是用于管理存储设备上数据组织与存取的一种机制。 它是操作系统的重要组成部分,承担着对文件的创建、读写、组织、存储、访问控制等管理任务。 功能: 文件的创建与删除;文件的读写与访问&am…

【Linux】shell的条件判断

目录 一.使用逻辑运算符判定命令执行结果 二.条件判断方法 三.判断表达式 3.1文件判断表达式 3.2字符串测试表达式 3.3整数测试表达式 3.4逻辑操作符 一.使用逻辑运算符判定命令执行结果 && 在命令执行后如果没有任何报错时会执行符号后面的动作|| 在命令执行后…

Codeforces Round 1028 (Div. 2)(ABC)

A. Gellyfish and Tricolor Pansy 翻译: 水母和小花在玩一个叫 “决斗 ”的游戏。 水母有 a HP,花花有 b HP。 它们各有一个骑士。水母的骑士有 c HP,而花花的骑士有 d HP。 他们将进行一轮游戏,直到其中一方获胜。对于 k1、2、.…

智能化程度越高,算法“越狱”也会越来越多

前两天,有关美国人工智能(AI)公司OpenAI旗下推理大模型o3首次出现“不听人类指挥,拒绝关闭”的消息引发高度关注。这种现象应该不算技术性“错误”,而是算法(无意识性)“失误”——“算法越狱”…

Redis最佳实践——性能优化技巧之Pipeline 批量操作

Redis Pipeline批量操作在电商应用中的性能优化技巧 一、Pipeline核心原理与性能优势 1. 工作机制对比: sequenceDiagramtitle 常规请求 vs Pipeline请求# 常规模式Client->>Redis: 命令1Redis-->>Client: 响应1Client->>Redis: 命令2Redis--&g…

机器人学基础——正运动学(理论推导及c++实现)

机器人正运动学 机器人正运动学一般是指从机器人的关节位置到基于参考坐标系下末端执行器的位置。 平移变换和旋转变换 平移变换 假设我们有两个坐标系A和B,坐标系A与B的方位相同,xyz轴的指向都是一致的,即没有旋转变换。有一点p&#xf…

玉渊谭天:中方香会行动的三个细节 现场观察与国际反响

在第22届香格里拉对话会上,观察到了几个细节,这些细节揭示了中方在这次对话会上的行动。在第一场全体会议上,国防大学的张弛教授提问美国国防部长如何处理美国联盟与东盟国家之间的关系。柬埔寨等东盟国家代表向张弛表示感谢,认为他的提问触及了关键问题,反映了东盟国家的…

Python-13(永久存储)

创建并打开文件 open(file,mode)函数 该函数用于打开一个文件并返回对应的文件对象。 file参数指定的是文件路径和文件名,如果没有添加路径,那么默认将文件创建在python的主文件夹里面。mode参数指定的是打开的模式,r表示读取(…

linux驱动开发(1)-内核模块

内核模块 模块最大的好处是可以动态扩展应用程序的功能而无须重新编译链接生成新的应用程序镜像,在微软的Windows系统上动态链接库DLL(Dynamic Link Library),Linux系统上的共享库so(shared object)文件的…

【ISP算法精粹】动手实战:用 Python 实现 Bayer 图像的黑电平校正

在数字成像领域,图像信号处理器(ISP)如同幕后英雄,默默将传感器捕获的原始数据转化为精美的图像。而黑电平校正,作为ISP预处理流程中的关键一环,直接影响着最终图像的质量。今天,我们就通过Pyth…

【数据结构】顺序表和链表详解(上)

前言:上期我们介绍了算法的复杂度,知道的算法的重要性同时也了解到了评判一个算法的好与坏就去看他的复杂度(主要看时间复杂度),这一期我们就从顺序表和链表开始讲起。 文章目录 一,顺序表1,线性表2,顺序表…

【笔记】在 MSYS2(MINGW64)中安装 Python 工具链的记录

#工作记录 📌 安装背景 操作系统:MSYS2 MINGW64当前时间:2025年6月1日Python 版本:3.12(默认通过 pacman 安装)目标工具链: pipxnumpypipsetuptoolswheel 🛠️ 安装过程与结果记录…

sqli-labs靶场32-37关(宽字节注入)

目录 前言 less32(宽字节注入) less33(宽字节注入) less34(POST型宽字节注入) less35(数字型闭合宽字节) less36(宽字节注入) less37(POST…

SRE 基础知识:在站点可靠性工程中可以期待什么

作者:来自 Elastic Elastic Observability Team 在过去的 20 年里,大多数领先企业已经采用云计算和分布式系统来开发它们的应用程序。一个意想不到的后果是:传统的 IT 运维( IT operations - ITOps )常常难以应对日益增…

day16 leetcode-hot100-31(链表10)

25. K 个一组翻转链表 - 力扣(LeetCode) 1.模拟法 思路 将这个过程拆解为两个步骤,第一步将单分组的节点反转,第二步将反转后的链表加入原链表。 针对节点反转很容易,参考之前的206. 反转链表 - 力扣(Le…

黑马Java面试笔记之Redis篇(使用场景)

1.面试题 我看你做的项目中,都用到了redis,你在最近的项目中那些场景使用了redis呢 2.提问的底层逻辑 面试官提问你这个问题一是想验证你的项目场景的真实性,二是为了作为深入发问的切入点 3.延伸出来的知识点 3.1 缓存 缓存三兄弟&#x…