首页/开发/代码质量与评审速查/静态工厂方法(Static Factory Method 惯用法)
设计原则与模式62 条

静态工厂方法(Static Factory Method 惯用法)

用命名静态方法代替构造器:方法名可表达意图(of、valueOf、parse、create)、可缓存实例、可返回子类型;是 GoF 工厂方法在语言层面的常用变体。

静态工厂方法是什么

用有名字的静态方法代替构造器创建对象:方法名可以表达意图(of、valueOf、parse、format、create),返回值可以是子类型,也可以复用缓存实例。它是工厂方法模式在语言层面的轻量变体,Effective Java 把「考虑用静态工厂方法代替构造器」列为第一条建议。缺点是不易被继承扩展、无法通过反射按约定实例化。

基本信息

命名惯例of / valueOf / parse / format / create / newInstance
收益意图显式、实例可控、可返回子类型
对比构造函数重载靠参数类型区分,可读性差
代价类难以被继承;框架按构造器约定实例化时不适用

判断与用法

  • 多个重载构造器参数类型相同、语义不同时改用命名方法
  • 需要返回接口或抽象类的实现时,用静态工厂隐藏实现类
  • 实例可被复用(常量、值对象、枚举式有限集合)时,用工厂控制实例数量
  • 需要表达解析语义(parse)或格式化语义(format)时,命名比构造器清楚
  • 需要在创建时校验并给出明确异常信息时,把校验写在工厂里
  • 需要子类化定制时转向构造器或保护型工厂,而不是硬套静态方法

Java 示例

Java 示例
Money usd = Money.of("USD", 10);              // 语义清晰的创建入口
Instant t = Instant.parse("2026-10-12T00:00:00Z"); // 解析用 parse
List<String> empty = List.of();                // 复用不可变空实例
boolean b = Boolean.valueOf(true);              // 可缓存实例

// 缓存实例必须返回不可变对象,否则享元被调用方改坏
private static final Money ZERO = Money.of("CNY", 0);
public static Money zero() { return ZERO; }

命名惯例含义

方法名含义示例
from / of类型转换,参数是来源对象Date.from(instant)
valueOf与 of 同义的更啰嗦写法BigInteger.valueOf(n)
parse / format字符串解析与格式化LocalDate.parse(text)
create / newInstance每次返回新实例createBuffer()
getInstance返回实例,可能缓存或单例getInstance(type)
静态工厂的常见误用是行为不一致:同类里有的工厂会校验参数,有的不校验,调用方无法预期。约定一种风格并保持,比方法名本身更重要。
缓存实例时返回不可变对象:可变实例被缓存后,任何调用方修改都会影响所有拿到同一实例的地方,这类缺陷很难定位。

易错点

  • 静态工厂与构造器行为不一致:调用方难以预期,参数校验时有时无
  • 缓存实例后可被修改:享元被破坏,应返回不可变对象
  • 滥用命名工厂导致类被继承封闭:类无法被扩展,框架也无法按构造器约定实例化
  • 工厂方法承担过多逻辑:从创建变成服务编排,职责与命名都不再匹配

数据来源与参考

  • Joshua Bloch《Effective Java》· 条目「考虑用静态工厂方法代替构造器」
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌