[关闭]
@XingdingCAO 2017-11-01T12:12:48.000000Z 字数 2048 阅读 2010

Effective Java(第2版):item 1 —— Consider static factory methods instead of constructors

Java constructor


实际需求使其产生

说到构造实例,我们一定先想到一个public的构造方法,简单明了。但是这样的方法存在一些局限性,所以static factory mehtods静态工厂方法(返回实例引用的静态方法)就被前辈们创造出来了。注意!这个static factory方法和factory设计模式(Design Pattern:Reusable Object-Oriented Elements)并不是同一种东西。

和任何事物一样,静态工厂方法也具有其优缺点:

1. 优点:符合语义的取名

— 静态工厂方法名可以任意选取,赋予其符合人的语义,方便阅读。
— 由于它有着自己的名称,所以还带来了额外的好处:在使用构造方法构造实例时,如果你需要设计多个仅在参数顺序上不同(来使得参数签名不同)的构造方法,使用时就会增加API使用者的学习成本,而且容易造成无法在编译时就检测到的bug。相反使用多个恰当取名的静态方法,会减少API的学习成本,使代码可读性更好。

2. 优点:灵活创建实例

— 静态工厂方法可以更加灵活地决定是否创建新的实例(构造方法就是用来构造新实例的)。这个特性在不变的、单例的等instance-controlled(实例受限)的类中显得非常重要。例如,Boolean类中的静态方法valueOf(boolean)会返回提前构造好的实例:

```
    public static final Boolean TRUE = new Boolean(true);

    public static final Boolean FALSE = new Boolean(false);

    private final boolean value;

    public Boolean(boolean value) {
        this.value = value;
    }

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

```

3. 优点:面向接口

— 静态工厂方法不仅可以返回所在类的实例,也可以返回其所在类的子类实例。不仅类的class(即类型)被隐藏,而且返回值的class也可以根据调用静态工厂方法的参数的不同来产生相应的变化(即通过重载来得到原类型的不同子类型)。
— 由此,可以使得返回类型被隐藏,得到一个非常抽象简练的API,其本身已经趋向interface-based frameworks。再进一步,静态方法返回interface,而由于接口不能含有静态方法,通常的做法是将这个静态方法放入一个不可实例化的类中,而类的名称则为接口名加‘s’。
— 例如,Java Collections Framework有着32个不同的对Collection接口的实现(JDK 1.5)。几乎这些所有的实现都被一个不可实例化的类java.util.Collections中的静态工厂方法暴露出来,所有返回类型都是相对隐藏的。
— 这种面向接口的编程方式,带来了其他的好处:降低了模块之间的耦合,在后期维护升级时,可随意升级和更换模块而不用做出较大的代码变动(因为核心的功能早已在接口中定义,所以升级这一模块时,其他模块无需作过多变更)。

4. 优点:类型推导(已经过时

— 在创建泛型类的实例时,使用静态工厂方法可以省去构造函数的中填写的多余的类型参数(作者使用的JDK版本为1.5,该版本的编译器的类型推导type inference能力并不是很强。但是,从JDK1.7和JDK1.8版本的类型推导能力/算法已经大大进化,所以本例子已经过时)。例如:

  1. Map<String, List<String>> m = new HashMap<String, List<String>>(); //JDK1.5必须写全
  1. public static <K, V> HashMap<K, V> newInstance() { return new HashMap<K, V>(); }
  2. Map<String, List<String>> m = HashMap.newInstance(); //JDK1.5仅需在类中添加一个静态方法就可以实现更智能的类型推导
  3. Map<String, List<String>> m = new HashMap<>(); //JDK1.7的编译器已经更加智能,直接省去后面的参数即可

5.缺点:限制了继承

— 假如一个类仅提供public的静态工厂方法,而不提供publicprotected的构造方法,那么该类就丧失了“生育能力”(被子类继承的能力)。但是也不是很要紧,除了inheritance继承关系,作者也十分鼓励composition组装关系。

6.缺点:文档中不突出

— 静态工厂方法在阅读时和其他静态方法并没有明显的区别,这就导致文档中静态工厂方法很难像构造方法被区别显示,当然这一点可以人为地改造,使其在文档中突出显示,但是很多人并没有这样做。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注