Effective-Java-1考虑用静态工厂方法代替构造器

静态工厂方法与构造器不同的优点[1]

  1. 它们有名称 (静态方法)

    例:构造器 BigInteger(int, int, Random) 返回的 BigInteger 可能为素数,如果用名为 BigInteger.probablePrime 的静态工厂方法来表示,显然更为清楚 (1.4的发行版本中最终增加了这个方法)[2]

  2. 不必每次调用时都创建一个新对象 (可以将构建好的实例进行缓存并重复利用)

    Boolean.valueOf(boolean) 从来不创建对象。这种方法类似于 Flyweight模式(享元模式)。如果程序经常创建相同的对象,并且创建对象的代价高,这种技术将会极大的提升性能。[3]

  3. 可以返回原返回类型的任何子类型对象 (可以返回隐藏类的实例,将实现类隐藏将使得API十分简洁)[4]

  4. 创建参数化类型(泛型)实例的时候,使代码变得更加简洁 (类型推导 type inference)[5]

    1
    2
    3
    4
    5
    6
    7
    8
    // 调用参数化构造器时,指明类型
    Map<String, List<String>> map = new HashMap<String, List<String>>();
    // 假如在 HashMap 中提供静态工厂
    public static <K, V> HashMap<K, V> newInstance() {
    return new HashMap<K, V>();
    }
    // 创建实例将会变简洁
    Map<String, List<String>> map = HashMap.newInstance();

静态工厂方法的缺点

  1. 类如果不含公有的或者受保护的构造器,就不能被子类化

  2. 与其他的静态方法实际上没有任何区别

    在API文档中,静态工厂方法不会像构造器一样被单独列出并标识,对于仅提供静态工厂方法的类而言,想查到如何实例化该类是比较麻烦的。

    静态工厂方法的一些惯用名称如下:

    1. valueOf
    2. of
    3. getInstance
    4. newInstance
    5. getType
    6. newType

静态工厂方法和共有构造器各有用处,一般情况下静态工厂更加合适,优先提供静态工厂,而不是共有构造器[6]

个人总结: 静态工厂方法是对获取对象的一种封装(封装为静态方法),具体实现可隐藏于其中,具有更高的灵活性[7]


  1. Joshua Bloch, Effective Java, 3rd Edition, Item 1, frames static factory methods as an alternative to constructors and organizes their advantages and disadvantages. ↩︎

  2. Oracle Java SE 21 API, BigInteger.probablePrime(int, Random), documents a named static factory for returning a positive probable prime with the requested bit length. ↩︎

  3. Oracle Java SE 21 API, Boolean.valueOf(boolean), documents returning Boolean.TRUE or Boolean.FALSE; Erich Gamma et al., Design Patterns: Elements of Reusable Object-Oriented Software, describes the Flyweight pattern background for shared objects. ↩︎

  4. Oracle Java SE 21 API, EnumSet, is an abstract class whose instances are created through static factory methods, illustrating how callers can depend on an abstract API while implementations remain hidden. ↩︎

  5. Oracle, Java Language Specification §15.9 Class Instance Creation Expressions, defines class instance creation and modern diamond inference; this supports the historical type-inference motivation while also bounding it for newer Java versions. ↩︎

  6. Joshua Bloch, Effective Java, 3rd Edition, Item 1, recommends considering static factory methods instead of constructors while preserving the tradeoff that both creation forms have uses. ↩︎

  7. Oracle Java SE 21 API, ServiceLoader, documents service-provider loading through an abstraction, which is one official example of object acquisition being mediated by an API rather than direct construction. ↩︎