170606-静态工厂方法的优缺点

静态工厂方法的优缺点

什么是静态工厂方法

一般而言,如果一个类需要调用另一个类的变量和方法,那么该类需要先获得另一个类的实例,最常用的的方法就是被调用类提供一个公有的构造方法。但是,还要另外一种方法,就是被调用类提供一个可以返回该类实例的静态方法,该静态方法称为静态工厂方法。

例如下面的例子(引自《Effective Java》),将boolean基本类型值转换成了一个Boolean对象引用:

1
2
3
public static Boolean valueOf(boolean b) {
return b ? Boolean.TRUE : Boolean.FALSE;
}

优点

  1. 和构造方法不一样,静态工厂方法可以有自己明确的名字。比如newInstance、getInstance、valueOf,可以更明确知道这些方法名字的意思。而构造方法只能通过new类名来创建,比如Person person = new Person()。

  2. 不必没次调用时都创建一个新对象。使用静态工厂方法对外提供单例,其实就是提前准备好实例,这样可以重复利用,减少重复创建实例,不过这也需要注意线程安全问题。

  3. 可以返回原返回类型的任何子类的对象。这个可以这么理解,例如EnumSet类,EnumSet是抽象类是不能被实例化的,但是可以通过里面的noneOf静态工厂方法返回它子类的对象,RegularEnumSet和JumboEnumSet都是EnumSet的子类,代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E>
    implements Cloneable, java.io.Serializable {

    EnumSet(Class<E>elementType, Enum[] universe) {}

    public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
    if (universe.length <= 64)
    return new RegularEnumSet<>(elementType, universe);
    else
    return new JumboEnumSet<>(elementType, universe);
    }
    }
  4. 在创建参数化类型实例的时候,它们使代码变得更加简洁。这条可以这么理解,比如在创建一个Map类型对象时,我们一般可以这么创建:

1
Map<String, List<String>> m = new HashMap<String, List<String>>();

但是在JDK7以上的版本,泛型参数是可以被推导出来的,所以可以有更简洁的写法:
Map<String, List<String>> m = new HashMap<>();

缺点

  1. 类如果不含有公有的或者受保护的构造方法,就不能被继承。如果使用静态工厂方法获得实例,而不提供公有的构造方法,把构造方法写为私有private,那么该类就不能被继承扩展,这就是使用复合而不是继承来扩展类了。

  2. 与其他的静态方法实际上没有任何区别。静态工厂方法其实和其他普通的静态方法是一样的,如果没有加以说明,两者不能很好被区分开来,会造成使用者不知道怎么获取该类的实例,而且不能清晰查明该类是如何被实例化的。

总结

简而言之,静态工厂方法和公有构造方法都各有用处,我们需要理解它们各自的长处。静态工厂通常更加合适,因此切忌第一反应就是提供公有的构造器,而不先考虑静态工厂。

参考资料

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×