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

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

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

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

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

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

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

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

    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

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

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