1: 考虑用静态工厂方法代替构造器
1. 概述
让类提供一个公有的静态工厂方法来产生该类的实例。
2. 举例
public static Boolean valueOf(boolean b){
return b ? Boolean.TRUE : Boolean.FALSE;
}
注意:静态工厂方法与设计模式中的工厂模式不同。
3. 优势
3.1 主要优势介绍
- 1.静态工厂方法与构造器第一大不同时,它们有名称。
- 2.第二大优势在于,不必每次调用他们的时候都创建一个新对象。
- 3.第三大优势在于,它们可以返回原类型的任何子类型对象。
- 4.第四大优势在于,在创建参数化类型实例的时候,它们使代码变得简洁。
3.2 优势详解
优势一:它们有名称
如果构造器的参数本身并没有确切的描述正被返回的对象,那么具有适当名称的静态工厂方法会更容易使用,产生的客户端代码也更容易阅读。
比如:构造器
BigInteger(int, int, Random)
返回的BigInteger可能是素数,如果用名为BigInteger.probablePrime的静态工厂方法来表示显然更为清楚(jdk1.4后加入了这个方法)。优势二:不必每次调用他们的时候都创建一个新对象
对于不可变类,可以通过使用静态工厂方法预先构件好的实例,或者将构建好的实例缓存起来,进行重复利用,从而避免创建不必要的重复对象。
比如Boolean.valueOf(boolean)方法:这个方法从来不创建对象(看开头的代码),这种方式类似于Flyweight模式。如果程序经常请求创建相同的对象,并且创建对象的代价很高,这项技术可以极大地提升性能。
优势三:它们可以返回原类型的任何子类型对象
这种灵活性的一种应用是:API可以返回对象,同时又不会使对象的类变成公有的。以这种方式隐藏实现类会使API变得非常简洁。
比如,java collections framework 的集合接口中有32个便利实现,分别提供了不可修改的集合、同步集合等。几乎所有的实现都通过静态工厂方法在一个不可实例化的类(java.util.Collections)中导出。所有返回对象的类都是非公有的。
现在已经改了,改的更优雅了,后面补充。
优势四:在创建参数化类型实例的时候,它们使代码变得简洁
这里主要是指类型推导。
比如,我们创建一个HashMap需要这样:
Map<String, List<String>> map = new HashMap<String, List<String>>();
烦的不行,但是,如果你的HashMap里有这样一个方法:
public static HashMap<K, V> newInstance() {
return new HashMap<K, V>();
}
这样,你创建一个Hashmap只需要:
Map<String, List<String>> map = HashMap.newInstance();
jdk1.7开始已经开始支持类型推导了。effective java这本书的作者在写书的时候,jdk还停留在1.6,当时并没有类型推导这种功能。作者在书里是这样写的:“总有一天,java能在构造器调用以及方法调用中执行这种推导”。事实证明,他是对的,膜拜一下。
4. 缺点
1.第一个缺点是:类如果不含公有的或者受保护的构造器,就不能被子类化。
例如,要想将 java collections framework 中的任何方便的实现子类化,是做不到的。当然,这也可能因祸得福,因为好的设计鼓励使用组合(复合)而不是继承。
2.第二个缺点是:它与其他的静态方法实际上没有任何区别。
在 javadoc 文档中,它没有像构造器那样被特殊的标识出来。作者书中说:“总有一天,javadoc工具会注意到静态工厂方法”。因为我也没用过javadoc ,所以现在有没有支持我也不清楚,有时间去瞅瞅。
5. 总结
简而言之,静态工厂方法和公有构造器都各有用处。静态工厂方法通常更加合适,因此,切记第一反应就是提供公有构造器而不优先考虑静态工厂。