effective|Item1: 考虑使用静态工厂方法代替构造方法

1 什么是静态工厂方法 静态工厂方法不是指设计模式中的工厂方法,而是在类中提供一个静态方法,该类方法返回类的一个实例。
在Java API中有许多这样的例子,如所有的基本对象的包装类都会提供一个valueOf()的方法用于获取该对象的实例:

String str = String.valueOf(1); Integer integer = Integer.valueOf("1"); Long lon = Long.valueOf("1"); Double dou = Double.valueOf("1");

2 静态工厂方法的好处 2.1 静态工厂方法可以有名字,而构造方法无法命名 编程中起名字很重要,不管是变量名还是方法名,最好能让人见名知意,易于阅读。比如BigInteger.probablePrime方法,返回一个可能为素数的BigInteger。
在当需要提供多个构造方法,而构造方法之间可能仅仅是参数顺序不一样,这样很容易引发错误。而静态工厂方法完全可以避免这种问题
2.2 静态工厂方法不一定要创建一个新对象 【effective|Item1: 考虑使用静态工厂方法代替构造方法】这一点在单例模式中有很好的体现。通过将构造方法私有,再提供一个静态方法每次返回同一个实例。
还有一种常见的情况,如果对象的创建成本很高,为了提高效率,不会每次都创建一个新对象,而是使用对象池,将用完的对象放入该池中,当需要一个对象时,通过静态工厂方法返回,方法内部判断对象池中是否有空闲对象,如果没有再创建新对象。
2.3 静态工厂方法可以返回其返回类型的任何子类 首先来看例子:
List emptyList = Collections.emptyList();
源码:
public static final List EMPTY_LIST = new EmptyList<>(); public static final List emptyList() { return (List) EMPTY_LIST; } private static class EmptyList extends AbstractList implements RandomAccess, Serializable { private static final long serialVersionUID = 8842843931221139166L; public Iterator iterator() { return emptyIterator(); } public ListIterator listIterator() { return emptyListIterator(); }public int size() {return 0; } public boolean isEmpty() {return true; }public boolean contains(Object obj) {return false; } public boolean containsAll(Collection c) { return c.isEmpty(); } public int hashCode() { return 1; } }

在源码中可以看到,该方法返回的是一个常量,而该常量是通过创建一个EmptyList对象,它是List的一个子类。
一般而言,对于一个接口Type(如这里的Collection),会提个一个Types的类(如这里的Collections),该类会提供私有构造方法,通过静态工厂方法放回示例,而其中大部分的类都对外隐藏,如上面看到的EmptyList类别设置为private。这样会使整个API更为紧凑。且当下次我要修改EmptyList的实现时,对使用者没有影响。
2.4 返回对象的类可以根据输入参数的不同而不同 2.5 返回对象的类不需要存在 3 缺点
  • 当构造方法被私有时,无法被继承(这个点倒是没有很理解,不私有构造方法就可以解决这个问题)
  • 程序员无法找到静态工厂方法。主要是指java doc不会把静态公共方法和构造方法放在一起,二是将其和其他普通方法放在一起
4 静态工厂方法常用的名字
  • from
  • of
  • valueOf
  • instance/getInstance
  • create/newInstance
  • getXxxx
  • newXxxx

    推荐阅读