在Spring框架中,工厂模式的应用非常广泛且深入,主要体现在Bean的实例化方式和框架内部的核心设计两个层面。Spring不仅支持传统的简单工厂、工厂方法和抽象工厂思想,还通过特有的FactoryBean接口对工厂模式进行了深度封装和扩展。
以下是这三种工厂模式在Spring中的具体应用解析:
一、简单工厂模式在Spring中的应用
简单工厂模式的核心是“一个工厂类根据参数创建不同对象”。在Spring中,这主要体现为静态工厂方法创建Bean。
1. 配置方式
当我们需要通过某个类的静态方法来获取Bean实例时,可以使用class属性指定工厂类,factory-method指定静态方法。
<!-- XML配置示例 --><beanid="airplane"class="com.example.factory.AirPlaneFactory"factory-method="createAirPlane"><constructor-argvalue="Boeing"/></bean>2. 应用场景
第三方库集成:当需要整合一些没有无参构造函数、或者必须通过特定静态工具类获取实例的老旧系统或第三方SDK时。
简化配置:对于逻辑简单的对象创建,避免编写复杂的Java Config代码。
二、工厂方法模式在Spring中的应用
工厂方法模式的核心是“定义创建接口,让子类决定实例化哪一个类”。在Spring中,这体现为实例工厂方法创建Bean。
1. 配置方式
与静态工厂不同,实例工厂需要先创建工厂Bean本身,再通过factory-bean引用该工厂,factory-method调用其非静态方法。
<!-- XML配置示例 --><!-- 1. 先创建工厂实例 --><beanid="airPlaneFactory"class="com.example.factory.AirPlaneInstanceFactory"/><!-- 2. 通过工厂实例创建目标Bean --><beanid="airplane2"factory-bean="airPlaneFactory"factory-method="createAirPlane"><constructor-argvalue="Airbus"/></bean>2. 应用场景
依赖注入工厂:当工厂本身也需要依赖其他Spring管理的Bean(如数据源、配置信息)时,必须使用实例工厂,因为静态方法无法享受Spring的依赖注入特性。
动态策略选择:根据运行时上下文动态决定创建哪种实现类,符合开闭原则。
三、抽象工厂模式与Spring的深度结合:FactoryBean
这是Spring对工厂模式最精妙、最核心的应用。Spring提供了org.springframework.beans.factory.FactoryBean接口,它不仅仅是一个设计模式的实现,更是Spring容器扩展能力的基石。
1. 核心原理
FactoryBean是一个特殊的Bean,它本身是一个工厂,用来生产另一个Bean。
getObject():定义生产复杂对象的具体逻辑。
getObjectType():返回生产对象的类型,用于Spring的类型匹配和自动装配。
isSingleton():决定生产的对象是单例还是原型。
2. Spring内部的智能处理
Spring容器在初始化时,如果检测到某个Bean实现了FactoryBean接口:
不会直接返回FactoryBean实例,而是调用其getObject()方法,将返回的对象注册到容器中。
特殊访问机制:
context.getBean(“myBean”):获取的是FactoryBean生产的产品对象。
context.getBean(“&myBean”):获取的是FactoryBean工厂本身(通过添加&前缀)。
3. 典型应用场景
FactoryBean在Spring生态中无处不在,主要用于处理复杂对象的创建,这些对象往往无法通过简单的构造函数或Setter完成初始化:
MyBatis整合:SqlSessionFactoryBean是典型的FactoryBean,它负责解析MyBatis配置文件、构建数据源、创建SqlSessionFactory。我们在Spring中注入的其实是SqlSessionFactory,而不是FactoryBean本身。
AOP代理对象:Spring AOP生成的代理对象(Proxy)通常也是通过类似的工厂机制创建的,确保代理对象正确包裹目标Bean。
JNDI查找:JndiObjectFactoryBean用于从JNDI环境中查找资源(如DataSource),将复杂的JNDI查找逻辑封装在工厂内部。
延迟初始化与复杂构建:当Bean的创建过程涉及网络连接、文件IO或复杂的计算逻辑时,使用FactoryBean可以将这些逻辑封装,保持配置简洁。
四,简单工厂模式java代码完整示例:
简单工厂模式(Simple Factory Pattern)又称静态工厂方法模式,其核心思想是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类的实例。虽然它不属于 GoF 23 种设计模式之一,但在实际开发中非常常用,能有效解耦客户端与具体产品的依赖。
以下是一个完整的、可运行的 Java 代码示例,模拟一个图形绘制系统:系统支持绘制圆形、矩形和正方形,通过简单工厂模式统一创建图形对象。
1. 核心角色定义
第一步:定义抽象产品(Product)
所有具体图形必须实现的接口或抽象类。
/** * 抽象产品:图形接口 */publicinterfaceShape{voiddraw();}第二步:定义具体产品(Concrete Product)
实现抽象接口的具体图形类。
/** * 具体产品:圆形 */publicclassCircleimplementsShape{@Overridepublicvoiddraw(){System.out.println("Inside Circle::draw() method.");}}/** * 具体产品:矩形 */publicclassRectangleimplementsShape{@Overridepublicvoiddraw(){System.out.println("Inside Rectangle::draw() method.");}}/** * 具体产品:正方形 */publicclassSquareimplementsShape{@Overridepublicvoiddraw(){System.out.println("Inside Square::draw() method.");}}第三步:定义工厂类(Factory)
这是简单工厂模式的核心,包含一个静态方法,根据传入的类型标识创建对应的对象。
/** * 简单工厂类:ShapeFactory * 负责根据类型字符串创建具体的 Shape 对象 */publicclassShapeFactory{// 使用静态方法,方便客户端直接调用,无需实例化工厂publicstaticShapegetShape(StringshapeType){if(shapeType==null){returnnull;}// 忽略大小写比较,提高健壮性if(shapeType.equalsIgnoreCase("CIRCLE")){returnnewCircle();}elseif(shapeType.equalsIgnoreCase("RECTANGLE")){returnnewRectangle();}elseif(shapeType.equalsIgnoreCase("SQUARE")){returnnewSquare();}returnnull;}}2. 客户端调用(Client)
客户端只需要知道工厂类和抽象产品接口,完全不需要知道具体产品类(Circle, Rectangle 等)的存在。
publicclassClient{publicstaticvoidmain(String[]args){// 1. 获取圆形对象并绘制Shapecircle=ShapeFactory.getShape("CIRCLE");if(circle!=null){circle.draw();}// 2. 获取矩形对象并绘制Shaperectangle=ShapeFactory.getShape("RECTANGLE");if(rectangle!=null){rectangle.draw();}// 3. 获取正方形对象并绘制Shapesquare=ShapeFactory.getShape("SQUARE");if(square!=null){square.draw();}// 4. 测试无效输入Shapeunknown=ShapeFactory.getShape("TRIANGLE");if(unknown==null){System.out.println("Unknown shape type requested.");}}}3. 运行结果
InsideCircle::draw()method.InsideRectangle::draw()method.InsideSquare::draw()method.Unknownshape type requested.4. 代码结构解析与优缺点
优点
解耦:客户端(Client)不再直接使用 new Circle() 或 new Rectangle(),而是依赖 ShapeFactory 和 Shape 接口。如果未来修改了具体产品的构造函数或初始化逻辑,只需修改工厂类,客户端代码无需变动。
简化客户端代码:客户端无需关心对象创建的复杂细节,只需传递一个简单的参数即可获取所需对象。
集中管理:对象的创建逻辑集中在一个地方,便于维护和统一控制(例如可以在工厂中加入缓存逻辑,实现单例或对象池)。
缺点
违反开闭原则(OCP):这是简单工厂模式最大的缺陷。如果需要新增一种图形(如三角形 Triangle),必须修改 ShapeFactory 类中的 getShape 方法,增加新的 if-else 或 switch-case 分支。在大型系统中,这会导致工厂类变得非常臃肿且难以维护。
职责过重:工厂类承担了所有产品的创建逻辑,一旦工厂类出错,整个系统的对象创建都会受到影响。
5. 适用场景
产品种类相对固定,不会频繁新增。
客户端只关心最终得到的产品对象,而不关心其创建过程。
创建逻辑比较简单,不需要复杂的层级结构。
提示:如果产品种类频繁扩展,建议升级为工厂方法模式(Factory Method Pattern),通过让子类决定实例化哪一个类来符合开闭原则。
工厂方法模式的Java完整代码示例:
工厂方法模式(Factory Method Pattern)的核心在于定义一个创建对象的接口,但让子类决定实例化哪一个类。它将对象的实例化过程延迟到子类中,从而符合“开闭原则”(对扩展开放,对修改关闭)。
以下是一个完整的、可运行的 Java 代码示例,模拟一个日志记录器系统:系统支持多种日志记录方式(如控制台日志、文件日志),通过工厂方法模式实现解耦。
1. 核心角色定义
第一步:定义抽象产品(Product)
这是所有具体产品必须实现的接口或抽象类。
/** * 抽象产品:日志记录器接口 */publicinterfaceLogger{voidlog(Stringmessage);}第二步:定义具体产品(Concrete Product)
实现抽象产品的具体类。
/** * 具体产品:控制台日志记录器 */publicclassConsoleLoggerimplementsLogger{@Overridepublicvoidlog(Stringmessage){System.out.println("[Console Log]: "+message);}}/** * 具体产品:文件日志记录器 */publicclassFileLoggerimplementsLogger{@Overridepublicvoidlog(Stringmessage){// 模拟写入文件操作System.out.println("[File Log]: Writing to file -> "+message);}}第三步:定义抽象工厂(Creator)
声明工厂方法,该方法返回抽象产品类型的对象。
/** * 抽象工厂:日志工厂接口 * 核心:定义创建 Logger 的规范,但不指定具体创建哪个 Logger */publicabstractclassLoggerFactory{/** * 工厂方法:由子类实现具体的创建逻辑 * @return Logger 实例 */publicabstractLoggercreateLogger();/** * 业务方法:使用创建出的 Logger 进行日志记录 * 注意:这里依赖的是抽象产品 Logger,而不是具体实现 */publicvoidwriteLog(Stringmessage){Loggerlogger=this.createLogger();logger.log(message);}}第四步:定义具体工厂(Concrete Creator)
重写工厂方法,返回具体的产品实例。
/** * 具体工厂:控制台日志工厂 * 负责创建 ConsoleLogger */publicclassConsoleLoggerFactoryextendsLoggerFactory{@OverridepublicLoggercreateLogger(){returnnewConsoleLogger();}}/** * 具体工厂:文件日志工厂 * 负责创建 FileLogger */publicclassFileLoggerFactoryextendsLoggerFactory{@OverridepublicLoggercreateLogger(){returnnewFileLogger();}}2. 客户端调用(Client)
客户端只依赖抽象工厂和抽象产品,完全不知道具体产品的存在。
publicclassClient{publicstaticvoidmain(String[]args){System.out.println("=== 测试控制台日志 ===");// 1. 创建具体工厂LoggerFactoryconsoleFactory=newConsoleLoggerFactory();// 2. 通过工厂执行业务逻辑(内部会自动创建 ConsoleLogger)consoleFactory.writeLog("系统启动成功");System.out.println("\n=== 测试文件日志 ===");// 1. 创建另一个具体工厂LoggerFactoryfileFactory=newFileLoggerFactory();// 2. 通过工厂执行业务逻辑(内部会自动创建 FileLogger)fileFactory.writeLog("用户登录异常: ID=1001");System.out.println("\n=== 扩展性演示 ===");// 如果未来需要增加 DatabaseLogger,只需新增 DatabaseLogger 类和 DatabaseLoggerFactory 类// 无需修改现有的 LoggerFactory、ConsoleLoggerFactory 或 Client 代码}}3. 运行结果
===测试控制台日志===[ConsoleLog]:系统启动成功===测试文件日志===[FileLog]:Writingtofile->用户登录异常:ID=1001===扩展性演示===4. 代码结构解析与优势
解耦创建与使用:
Client 类中没有任何 new ConsoleLogger() 或 new FileLogger() 的代码。
Client 只依赖于 LoggerFactory 和 Logger 这两个抽象层。
符合开闭原则(OCP):
扩展:如果需要新增一种“数据库日志”,只需新建 DatabaseLogger 实现 Logger 接口,并新建 DatabaseLoggerFactory 继承 LoggerFactory。
不修改:原有的 ConsoleLoggerFactory、FileLoggerFactory 以及 Client 代码完全不需要改动。
单一职责:
每个具体工厂类只负责创建一个特定的产品,逻辑清晰,避免了简单工厂模式中巨大的 if-else 或 switch-case 判断块。
5. 与简单工厂模式的对比
| 特性 | 简单工厂模式 | 工厂方法模式 |
|---|---|---|
| 工厂结构 | 只有一个静态工厂类 | 有一个抽象工厂基类,多个具体工厂子类 |
| 新增产品 | 需修改工厂类的 if-else 逻辑 | 新增一个具体工厂类,无需修改旧代码 |
| 开闭原则 | 违反(修改了现有代码) | 符合(仅扩展新代码) |
| 适用场景 | 产品种类少且固定 | 产品种类多且可能频繁扩展 |
这个示例展示了工厂方法模式如何通过多态和继承机制,将对象创建的复杂性封装在子类中,是大型框架(如 Spring、JDBC驱动加载)中非常常见的设计手法。
抽象工厂java代码完整示例
抽象工厂模式(Abstract Factory Pattern)是一种创建型设计模式,它提供一个接口或抽象类,用于创建一系列相关或相互依赖的对象,而无需指定它们具体的类。
以下是一个完整的、可运行的 Java 代码示例,模拟一个跨平台 UI 组件库:系统需要同时创建按钮(Button)和文本框(TextField),且必须保证同一套界面风格(如 Windows 风格或 Mac 风格)的一致性。
1. 核心角色定义
第一步:定义抽象产品(Abstract Products)
定义一组相关产品的接口。在这个例子中,我们有两种产品:按钮和文本框。
/** * 抽象产品 A:按钮接口 */publicinterfaceButton{voidrender();voidonClick();}/** * 抽象产品 B:文本框接口 */publicinterfaceTextField{voidrender();voidinputText(Stringtext);}第二步:定义具体产品(Concrete Products)
实现抽象产品接口的具体类,分为不同的产品族(Windows 族和 Mac 族)。
// --- Windows 产品族 ---/** * 具体产品 A1:Windows 按钮 */publicclassWindowsButtonimplementsButton{@Overridepublicvoidrender(){System.out.println("Render a button in Windows style.");}@OverridepublicvoidonClick(){System.out.println("Bind Windows click event listener.");}}/** * 具体产品 B1:Windows 文本框 */publicclassWindowsTextFieldimplementsTextField{@Overridepublicvoidrender(){System.out.println("Render a text field in Windows style.");}@OverridepublicvoidinputText(Stringtext){System.out.println("Input text into Windows text field: "+text);}}// --- Mac 产品族 ---/** * 具体产品 A2:Mac 按钮 */publicclassMacButtonimplementsButton{@Overridepublicvoidrender(){System.out.println("Render a button in Mac OS style.");}@OverridepublicvoidonClick(){System.out.println("Bind Mac OS click event listener.");}}/** * 具体产品 B2:Mac 文本框 */publicclassMacTextFieldimplementsTextField{@Overridepublicvoidrender(){System.out.println("Render a text field in Mac OS style.");}@OverridepublicvoidinputText(Stringtext){System.out.println("Input text into Mac OS text field: "+text);}}第三步:定义抽象工厂(Abstract Factory)
声明一组用于创建不同产品的方法。每个方法对应一种产品类型。
/** * 抽象工厂接口 * 声明创建 Button 和 TextField 的方法 */publicinterfaceGUIFactory{ButtoncreateButton();TextFieldcreateTextField();}第四步:定义具体工厂(Concrete Factories)
实现抽象工厂接口,负责创建特定产品族(Windows 或 Mac)的所有产品。
/** * 具体工厂:Windows 工厂 * 负责创建 Windows 风格的一系列组件 */publicclassWindowsFactoryimplementsGUIFactory{@OverridepublicButtoncreateButton(){returnnewWindowsButton();}@OverridepublicTextFieldcreateTextField(){returnnewWindowsTextField();}}/** * 具体工厂:Mac 工厂 * 负责创建 Mac 风格的一系列组件 */publicclassMacFactoryimplementsGUIFactory{@OverridepublicButtoncreateButton(){returnnewMacButton();}@OverridepublicTextFieldcreateTextField(){returnnewMacTextField();}}2. 客户端调用(Client)
客户端只依赖抽象工厂和抽象产品接口。通过切换具体的工厂实例,可以一键切换整个产品族。
publicclassApplication{privateButtonbutton;privateTextFieldtextField;/** * 构造函数接收抽象工厂,不关心具体是哪种工厂 */publicApplication(GUIFactoryfactory){this.button=factory.createButton();this.textField=factory.createTextField();}publicvoidpaint(){button.render();button.onClick();textField.render();textField.inputText("Hello Abstract Factory!");}publicstaticvoidmain(String[]args){System.out.println("=== 运行在 Windows 环境下 ===");// 1. 创建 Windows 工厂GUIFactorywindowsFactory=newWindowsFactory();// 2. 将工厂传入应用ApplicationappWindows=newApplication(windowsFactory);// 3. 执行绘制,所有组件都是 Windows 风格appWindows.paint();System.out.println("\n=== 运行在 Mac 环境下 ===");// 1. 创建 Mac 工厂GUIFactorymacFactory=newMacFactory();// 2. 将工厂传入应用ApplicationappMac=newApplication(macFactory);// 3. 执行绘制,所有组件都是 Mac 风格appMac.paint();}}3. 运行结果
===运行在Windows环境下===Rendera button inWindowsstyle.BindWindowsclick eventlistener.Rendera text field inWindowsstyle.Inputtext intoWindowstext field:HelloAbstractFactory!===运行在Mac环境下===Rendera button inMacOSstyle.BindMacOSclick eventlistener.Rendera text field inMacOSstyle.Inputtext intoMacOStext field:HelloAbstractFactory!4. 代码结构解析与优势
产品族一致性:
Application 类中,button 和 textField 是由同一个工厂对象创建的。
如果使用 WindowsFactory,那么得到的必然是 WindowsButton 和 WindowsTextField,绝不会出现“Windows 按钮”搭配“Mac 文本框”这种风格不一致的情况。
符合开闭原则:
扩展新系列:如果未来需要支持 Linux 风格,只需新增 LinuxButton、LinuxTextField 和 LinuxFactory,无需修改现有的 WindowsFactory、MacFactory 或 Application 代码。
缺点:如果需要在产品族中增加一个新的产品类型(例如增加一个 Checkbox 复选框),则必须修改抽象工厂接口 GUIFactory 以及所有具体工厂类,这违反了开闭原则。因此,抽象工厂模式适用于产品结构稳定,但产品族经常切换的场景。
解耦:
客户端代码(Application)完全不依赖具体的产品类(如 WindowsButton),只依赖抽象接口。这使得代码更容易测试和维护。
5. 与工厂方法模式的对比
| 特性 | 工厂方法模式 | 抽象工厂模式 |
|---|---|---|
| 关注点 | 单个产品的创建 | 一系列相关/依赖产品族的创建 |
| 产品维度 | 单一维度(如只有 Button) | 多个维度(如 Button + TextField + Checkbox) |
| 实现方式 | 通过继承,子类重写工厂方法 | 通过组合,工厂内部包含多个工厂方法 |
| 适用场景 | 只需要创建一个对象,且希望解耦创建逻辑 | 需要确保创建的一组对象属于同一系列,且风格一致 |
这个示例展示了抽象工厂模式如何通过封装一组工厂方法,确保客户端获取到的是一整套协调一致的对象,是构建跨平台应用、主题切换系统时的经典选择。
四、总结对比
| 模式类型 | Spring中的体现 | 核心特点 | 适用场景 |
|---|---|---|---|
| 简单工厂 | 静态工厂方法 (factory-method) | 通过类的静态方法创建,无需实例化工厂 | 创建逻辑简单,工厂无状态,不依赖其他Bean |
| 工厂方法 | 实例工厂方法 (factory-bean) | 通过Bean实例的非静态方法创建 | 工厂需要依赖其他Spring Bean,或需要状态管理 |
| 抽象工厂/高级应用 | FactoryBean 接口 | 标准化接口,Spring容器特殊识别,支持复杂构建逻辑 | 创建过程复杂、需要介入容器生命周期、整合第三方框架(如MyBatis、Hibernate) |
核心结论:
在日常Spring开发中,我们很少手动编写简单的工厂类,因为Spring IOC容器本身就是一个巨大的工厂。但在整合第三方框架或创建极其复杂的Bean时,FactoryBean是Spring提供的最强大、最标准的扩展点,它完美诠释了工厂模式在框架设计中的价值:屏蔽复杂创建细节,提供统一的获取接口。