@XingdingCAO
2017-11-01T12:12:48.000000Z
字数 2048
阅读 2010
Java
constructor
说到构造实例,我们一定先想到一个public
的构造方法,简单明了。但是这样的方法存在一些局限性,所以static factory mehtods
静态工厂方法(返回实例引用的静态方法)就被前辈们创造出来了。注意!这个static factory
方法和factory
设计模式(Design Pattern:Reusable Object-Oriented Elements)并不是同一种东西。
— 静态工厂方法名可以任意选取,赋予其符合人的语义,方便阅读。
— 由于它有着自己的名称,所以还带来了额外的好处:在使用构造方法构造实例时,如果你需要设计多个仅在参数顺序上不同(来使得参数签名不同)的构造方法,使用时就会增加API使用者的学习成本,而且容易造成无法在编译时就检测到的bug。相反使用多个恰当取名的静态方法,会减少API的学习成本,使代码可读性更好。
— 静态工厂方法可以更加灵活地决定是否创建新的实例(构造方法就是用来构造新实例的)。这个特性在不变的、单例的等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);
}
```
— 静态工厂方法不仅可以返回所在类的实例,也可以返回其所在类的子类实例。不仅类的class
(即类型)被隐藏,而且返回值的class
也可以根据调用静态工厂方法的参数的不同来产生相应的变化(即通过重载来得到原类型的不同子类型)。
— 由此,可以使得返回类型被隐藏,得到一个非常抽象简练的API,其本身已经趋向interface-based frameworks。再进一步,静态方法返回interface
,而由于接口不能含有静态方法,通常的做法是将这个静态方法放入一个不可实例化的类中,而类的名称则为接口名加‘s’。
— 例如,Java Collections Framework
有着32个不同的对Collection
接口的实现(JDK 1.5)。几乎这些所有的实现都被一个不可实例化的类java.util.Collections
中的静态工厂方法暴露出来,所有返回类型都是相对隐藏的。
— 这种面向接口的编程方式,带来了其他的好处:降低了模块之间的耦合,在后期维护升级时,可随意升级和更换模块而不用做出较大的代码变动(因为核心的功能早已在接口中定义,所以升级这一模块时,其他模块无需作过多变更)。
— 在创建泛型类的实例时,使用静态工厂方法可以省去构造函数的中填写的多余的类型参数(作者使用的JDK版本为1.5,该版本的编译器的类型推导type inference
能力并不是很强。但是,从JDK1.7和JDK1.8版本的类型推导能力/算法已经大大进化,所以本例子已经过时)。例如:
Map<String, List<String>> m = new HashMap<String, List<String>>(); //JDK1.5必须写全
public static <K, V> HashMap<K, V> newInstance() { return new HashMap<K, V>(); }
Map<String, List<String>> m = HashMap.newInstance(); //JDK1.5仅需在类中添加一个静态方法就可以实现更智能的类型推导
Map<String, List<String>> m = new HashMap<>(); //JDK1.7的编译器已经更加智能,直接省去后面的参数即可
— 假如一个类仅提供public
的静态工厂方法,而不提供public
或protected
的构造方法,那么该类就丧失了“生育能力”(被子类继承的能力)。但是也不是很要紧,除了inheritance
继承关系,作者也十分鼓励composition
组装关系。
— 静态工厂方法在阅读时和其他静态方法并没有明显的区别,这就导致文档中静态工厂方法很难像构造方法被区别显示,当然这一点可以人为地改造,使其在文档中突出显示,但是很多人并没有这样做。