在SpringBoot这类依赖注入环境中,创建型设计模式是否没有实用价值?
先明确两个技术的核心定位差异
- 依赖注入(DI)的核心作用是解耦对象依赖的声明和依赖的获取/生命周期管理,它解决的是架构层面的依赖耦合问题,帮你把业务代码里直接调用
new创建依赖的逻辑剥离掉,统一交给DI容器处理。 - 工厂模式的核心作用是封装一类对象的创建逻辑,支持动态选择实现类、收敛复杂初始化规则,它解决的是「对象创建规则太复杂、需要灵活扩展」的问题,和你是否使用DI没有本质冲突。
DI场景下工厂模式的核心价值体现在几个高频场景
运行时需要动态选择实现类
比如你开发一个支付模块,有AlipayHandler、WechatPayHandler、UnionPayHandler三个实现类,需要根据用户前端传入的payType参数返回对应的支付实现实例。这种依赖的选择逻辑是和运行时参数绑定的,DI容器本身没法提前帮你注入对应的实现,你总不能把三个实现类都注入到业务代码里自己写if-else判断吧?
这种场景下封装一个PaymentFactory,把支付实现的匹配逻辑收敛到工厂内部,你只需要把工厂注入到业务类,调用PaymentFactory.getHandler(payType)就能拿到对应实例,既符合开闭原则,新增支付方式只需要修改工厂逻辑,不需要动业务代码,也避免了业务类和多个支付实现强耦合。
复杂对象的初始化逻辑需要内聚
如果某个对象的创建需要经过多步参数计算、依赖组装、环境判断,比如你要创建一个跨云的存储客户端实例,需要根据当前环境配置的云厂商、秘钥、地域参数,还要做初始化连通性校验,不同云厂商的初始化逻辑还有差异。
如果把这些逻辑全写在DI的配置代码里,会导致DI配置极度臃肿,也不符合单一职责原则。这时候把整套创建逻辑封装到CloudStorageFactory里,DI容器只需要注入工厂实例,或者直接把工厂作为Bean的提供者注册到DI容器即可,所有创建逻辑内聚在工厂里,排查问题、修改规则都只需要改工厂类,维护成本低很多。
多实例/短生命周期实例的创建
很多场景下你需要的不是DI容器默认管理的单例实例,而是每次调用都生成新的实例,或者需要手动控制实例的创建和销毁时机,比如批量处理任务的工作实例、临时的数据库连接、请求上下文绑定的专用对象等。
这种场景下用工厂封装实例的创建/销毁逻辑,比你在业务代码里直接调用DI容器的API获取实例要优雅得多,也避免了业务代码和具体DI容器强耦合,后续切换DI框架不需要修改业务逻辑。
二者的配合其实非常普遍
绝大多数成熟的DI框架都原生支持工厂的集成,比如Spring里的FactoryBean接口,Guice里的Provider接口,本质上都是工厂模式的规范实现。甚至DI容器本身的底层,大量用到了抽象工厂模式来实现不同作用域、不同配置的Bean实例创建,工厂模式可以说是DI容器实现的核心基础之一。
你产生这个误区的核心原因是混淆了「不需要在业务代码里写
new」和「不需要处理对象创建逻辑」:DI只是把你业务代码里的new挪到了框架层或者配置层,但只要你有复杂的、动态的、需要扩展的对象创建需求,工厂模式的价值就永远存在。
内容的提问来源于stack exchange,提问作者Misa D.

