← 返回题目列表

静态工厂方法和工厂方法模式有什么区别?

高频 中等 第 9 / 25 题 更新于 2026/08/01
工厂方法模式静态工厂方法创建型模式API设计

简化版

静态工厂方法通常是类上的 of()valueOf()getInstance() 这类命名创建方法,本质是 API 写法;工厂方法模式则是把创建动作延迟到子类或具体工厂,通过多态扩展产品创建。前者偏“更好地封装构造器”,后者偏“让创建逻辑可扩展、可替换”。

详细版

静态工厂方法不是 GoF 工厂方法模式的同义词。它通常指一个静态方法返回对象,比如 LocalDate.of(2026, 8, 1)Integer.valueOf(100)。它可以有名称、可以缓存对象、可以返回子类型,也可以隐藏构造细节。

工厂方法模式强调的是抽象创建接口和多态扩展:客户端依赖 CreatorFactory 抽象,具体创建哪种产品由具体工厂决定。新增产品时,往往新增一个工厂类,而不是修改原有大分支。

维度静态工厂方法工厂方法模式
本质命名的静态创建 API多态创建模式
扩展方式修改静态方法内部逻辑较常见新增具体工厂/产品
是否依赖继承/接口不一定通常依赖抽象产品和抽象工厂
高频场景值对象、缓存、语义化构造插件、框架扩展、产品创建解耦

面试时可以这样答:静态工厂方法是构造器替代方案,工厂方法模式是创建职责解耦方案。两者都能封装创建,但扩展能力和设计意图不同。

完整版教学

一、先把名字拆开,不要被“工厂方法”四个字绕住

“静态工厂方法”里的工厂,更多是 API 命名习惯:不用 new,而是通过一个有语义的静态方法拿对象。“工厂方法模式”里的工厂,是设计模式角色:由抽象创建者声明创建方法,具体创建者决定实例化哪种产品。

示意:

静态工厂方法:User.of(name, age)
工厂方法模式:ParserFactory.createParser() -> JsonParser / XmlParser

两者都能隐藏构造细节,但前者不一定带来开放扩展结构,后者的核心就是把创建逻辑从使用方手里拿出来,并交给可替换的工厂层。

二、静态工厂方法解决什么问题

构造器只能用类名作为入口,无法表达创建语义。静态工厂方法可以用名字说明意图,比如 of 表示按参数创建,from 表示类型转换,valueOf 可能带缓存,getInstance 可能复用对象。

public final class Money {
    private final long cents;

    private Money(long cents) {
        this.cents = cents;
    }

    public static Money yuan(long yuan) {
        return new Money(yuan * 100);
    }

    public static Money cents(long cents) {
        return new Money(cents);
    }
}

如果传入数字 100,构造器 new Money(100) 不知道单位;Money.yuan(100)Money.cents(100) 则把语义说清楚。这里并没有复杂多态,只是 API 更清楚。

三、工厂方法模式解决什么问题

工厂方法模式的重点是让客户端依赖抽象,而不是依赖具体产品创建。比如系统支持 JSON、XML、YAML 三种解析器,业务代码只关心 Parser 接口,不关心具体类怎么 new。

public interface Parser {
    Document parse(String text);
}

public interface ParserFactory {
    Parser createParser();
}

public class JsonParserFactory implements ParserFactory {
    public Parser createParser() {
        return new JsonParser();
    }
}

新增 TomlParserFactory 时,不必修改使用 ParserFactory 抽象的业务流程。工厂方法的价值来自多态扩展,而不是来自“方法是静态还是实例”。

四、为什么静态方法常常不满足开闭原则

静态工厂方法也能根据参数返回不同子类,但如果它内部写了大分支,每次新增类型都要修改这个静态方法。比如新增一种支付渠道,需要改 Payment.create(type),这对频繁扩展的业务不友好。

public static Payment create(String type) {
    if ("wechat".equals(type)) return new WechatPayment();
    if ("alipay".equals(type)) return new AlipayPayment();
    throw new IllegalArgumentException(type);
}

假设一年新增 12 个渠道,这个方法会被反复修改 12 次,测试也要反复覆盖旧分支。若渠道由插件或独立团队扩展,注册表工厂、工厂方法或容器装配通常更合适。

记忆钩子:静态工厂方法让构造更好读,工厂方法模式让创建更好扩展。

五、两者可以组合使用

两种概念不是互斥的。具体工厂内部也可以使用静态工厂方法,静态工厂方法也可以返回工厂对象。关键是不要把组合后的代码误认为两者没有区别。

例如:

public final class ParserFactories {
    public static ParserFactory json() {
        return new JsonParserFactory();
    }
}

这里 ParserFactories.json() 是静态工厂方法,它返回的是一个具体工厂;而 JsonParserFactory.createParser() 才是在执行工厂方法模式里的产品创建职责。面试中能说出这一层,说明不是只背名词。

六、选择时看扩展频率和抽象边界

如果对象类型固定、创建逻辑简单、只是想隐藏构造器或做缓存,静态工厂方法很好。如果产品族持续扩展、创建逻辑由不同模块负责、使用方需要依赖抽象,工厂方法模式更合适。

判断问题更偏静态工厂方法更偏工厂方法模式
类型数量少且稳定多且常扩展
使用方可以知道返回类或抽象应只依赖抽象产品
创建逻辑简单集中由不同工厂分散承担
测试替换不强需要替换工厂或产品

一个实用标准是:如果新增类型必须改老代码,就不是很开放;如果新增类型只需要新增类和注册关系,扩展性会更好。

七、常见误区与追问

  • 误区:只要方法名叫 create 就是工厂方法模式。 是否是模式要看有没有抽象创建职责和多态扩展,不看方法名。
  • 误区:静态工厂方法一定比构造器高级。 简单对象用构造器也清楚,静态工厂适合需要命名语义、缓存或隐藏实现时。
  • 误区:工厂方法模式一定不能有 static。 static 可以作为辅助入口,但模式核心仍是抽象工厂方法和具体工厂多态。
  • 误区:静态工厂方法天然符合开闭原则。 内部大分支仍会导致新增类型时修改老代码。
  • 追问:Integer.valueOf 属于哪类? 它是静态工厂方法,带缓存语义,不是典型 GoF 工厂方法模式。
  • 追问:静态工厂方法能返回接口吗? 可以,这也是它隐藏实现的优点之一。
  • 追问:什么时候要从静态工厂演进到工厂方法? 当类型扩展频繁、创建逻辑分散、调用方需要替换工厂时。

八、加强记忆

这题记住两条线:静态工厂方法是“构造器 API 的改良”,工厂方法模式是“创建职责的多态解耦”。前者让创建更有语义,后者让新增产品更少改旧代码;判断时看扩展频率、抽象边界和测试替换需求。