← 返回题目列表

Java 框架中有哪些工厂方法模式的典型应用?

高频 中等 第 11 / 25 题 更新于 2026/07/28
工厂方法模式JavaSpringCalendarJDBC

简化版

Java 和常见框架里有很多创建逻辑被工厂封装的例子,例如 Calendar.getInstance()DocumentBuilderFactory.newInstance()、Spring 的 FactoryBean 和各种连接工厂。面试时重点不是硬说它们都完全等同于 GoF 工厂方法,而是说明它们都通过工厂入口隐藏具体产品创建。

详细版

典型例子可以这样讲:

  • Calendar.getInstance() 根据时区、Locale 等返回合适的 Calendar 实现,调用方不直接依赖具体日历类;
  • DocumentBuilderFactory.newInstance() 先获得工厂,再由工厂创建 DocumentBuilder
  • JDBC 里 DriverManager.getConnection() 屏蔽了具体数据库连接实现;
  • Spring 的 FactoryBean<T> 让一个 Bean 的创建过程由工厂对象控制;
  • 业务框架中的 ClientFactoryParserFactoryHandlerFactory 常用来隔离 SDK 或协议差异。

需要严谨一点:有些 API 更接近静态工厂或抽象工厂,不一定是标准 GoF 工厂方法结构。面试答案可以说“它们体现了工厂思想”,再指出具体差别,这比强行归类更准确。

完整版教学

一、Java 标准库里的工厂思想

标准库常通过静态方法或工厂类隐藏实现选择。比如 Calendar.getInstance() 返回抽象类型,内部可以根据环境选择具体实现。调用方只写:

Calendar calendar = Calendar.getInstance();

这让调用方无需知道具体日历类怎么创建,也保留了实现替换空间。

二、JAXP 里的工厂对象

XML 解析相关 API 常见两步创建:

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();

这里先获取工厂,再由工厂创建解析器对象。它体现了工厂封装复杂创建过程的价值,实际结构上也带有抽象工厂和服务发现的味道。

三、Spring 中的 FactoryBean

Spring 的 FactoryBean<T> 可以自定义某个 Bean 的创建逻辑。容器管理的是工厂对象,但对外暴露的是工厂生产出来的对象。

class ClientFactoryBean implements FactoryBean<Client> {
    public Client getObject() {
        return new Client(/* config */);
    }

    public Class<?> getObjectType() {
        return Client.class;
    }
}

这适合第三方客户端、复杂代理对象、需要初始化过程的对象。

四、框架例子要避免绝对化

很多框架 API 并不是教科书式的“抽象创建者 + 具体创建者 + 工厂方法”。例如静态工厂方法不一定等于工厂方法模式,DriverManager 更像注册表加工厂入口。

面试时可以说:这些例子体现了工厂封装创建、返回抽象、隔离具体实现的思想;如果严格按 GoF 分类,要看是否由子类决定创建哪种产品。

五、按结构而不是按方法名给框架 API 分类

看到 getInstance()newInstance() 不能立刻断言是 GoF 工厂方法。应追踪调用者拿到的是产品还是工厂、具体产品由静态分支、服务发现、注册表还是具体 Creator 决定,再说明它更接近哪种工厂结构。

Calendar.getInstance() -> 直接返回 Calendar 产品
DocumentBuilderFactory.newInstance() -> 先返回工厂
factory.newDocumentBuilder() -> 再创建产品
DriverManager.getConnection() -> 查已注册 Driver
FactoryBean.getObject() -> 容器委托工厂对象生产 Bean
这些 API 都隐藏创建细节
但只有满足 Creator 多态结构时才严格称 GoF 工厂方法

这段协作图要回答两个不同问题:产品由谁构造,具体工厂又由谁选择。工厂方法可以把产品构造从业务流程中移走,但应用入口、配置层或容器仍然必须决定使用哪个工厂;声称模式“消灭了所有分支”并不准确。

六、模式边界与扩展成本

维度本题结论
稳定抽象API 返回抽象类型并隐藏提供者发现、构造参数或代理生成细节。
主要变化点平台实现、服务提供者、驱动或容器中产品创建策略。
新增一种产品的动作按对应 SPI、注册协议或具体工厂扩展,而非一律继承某个 Creator。
不应放进工厂的职责把所有带 newInstance 名称的方法强行归成同一模式。
更轻或更合适的方案回答为“工厂思想/静态工厂/注册表/FactoryBean”,并准确指出与 GoF 结构差异。

是否符合开闭原则不能只数新增了多少类,而要看高风险旧代码是否仍被反复修改。若每次扩展仍要修改一个中心 switch、产品接口又泄漏具体类型,即使类名叫 Factory,也没有获得工厂方法的主要收益。

七、用三个测试验证设计没有走样

  1. 契约测试:对每个具体工厂执行同一组产品接口测试,确认返回值满足抽象契约。
  2. 扩展测试:加入一个假产品和假工厂,记录为了接入它修改了哪些旧文件。
  3. 未知类型测试:若存在注册表或参数路由,明确缺失 key 的异常类型和降级策略。
  4. 生命周期测试:连续创建两次,确认产品应当复用还是隔离,避免无意变成单例或重复昂贵连接。
  5. 依赖测试:具体构造参数应由工厂显式获得,业务类不应通过全局容器偷偷查找。
  6. 并发测试:注册表若支持运行期写入,必须定义发布、覆盖和读取的一致性;只读注册表则尽量启动期冻结。
  7. 可观测性测试:记录命中的工厂 key 与具体实现,排查配置选择错误时无需猜测。

记忆钩子:方法名只说明入口,调用链里的扩展点才决定模式。

八、常见误区与追问

  • 误区:Calendar.getInstance 是教科书式工厂方法结构。 它更常被归为静态工厂,未必有具体 Creator 子类覆写创建方法。
  • 误区:DriverManager 只体现工厂方法。 它还使用驱动注册表和路由选择。
  • 误区:FactoryBean 与 BeanFactory 是同一个接口。 前者自定义某个产品创建,后者是 Spring 容器核心工厂。
  • 追问:JAXP 为什么先拿工厂再拿 Builder? 实现发现与产品创建被分成两层,并可由提供者替换。
  • 追问:举框架例子时怎样保持严谨? 先说体现工厂思想,再按是否有 Creator 多态说明严格分类。
  • 追问:FactoryBean 取自身对象怎么做? 在 Spring 中通常使用 &beanName 获取工厂本身而不是其产品。

九、加强记忆

框架中的工厂应用不要死背类名,要抓住“隐藏具体实现、统一创建入口、返回抽象类型”三个特征。答题时先讲工厂思想,再谨慎说明它和标准工厂方法结构的差异,会显得更专业。