《第2章》创建和销毁对象(第1~6条)
【第1条】考虑用静态工厂方法代替构造函数
所谓静态工厂方法,实际上只是一个简单的静态方法,它返回的是类的一个实例。
使用静态工厂方法的好处:
1)它与构造函数不同,它有名字,你可以把名字起的更易于阅读。
如果你想让2个构造函数拥有相同个数和类型的参数,这将是无法实现的;即使是2个不同类型的参数顺序倒置的,使用者也非常容易搞混乱。
一个例子来自【第13条】,一个类Complex(复数,就是数学课上学的,有实数部和虚数部的那个东东)
对它的构造可能有这样2种需求:
a)分别给出实数部和虚数部来构造之;
b)基于极坐标来构造(提供“半径”和“角度”)
那么很显然这2中构造方式,都是由2个float型参数的,对于构造函数将无能为力,而静态工厂方法可以从方法名来区别开,而且还带来了易于辨识的好处:
- public class Complex {
- private final float re;
- private final float im;
- private Complex(float re, float im){
- this.re = re;
- this.im = im;
- }
- public static Complex valueOf(float re, float im){
- return new Complex(re, im);
- }
- public static Complex valueOfPolar(float r, float theta){
- return new Complex((float)(r * Math.cos(theta)), (float)(r * Math.sin(theta)));
- }
- }
注意:用静态工厂方法代替构造函数后,构造函数就成了private的了,当然如果你希望同时也提供公有的构造函数也是可以的。
2)它与构造函数不同,它每次被调用时,不要求非得创建一个新的对象。
也正是因为这个特性,才让我更加喜欢静态工厂方法。例如在全局唯一性对象中通过getInstance()方法提供对该对象的返回。
3)它与构造函数不同,它可以返回类型的子类型对象。
这样可以强迫使用者通过接口来引用被返回的对象,而不是通过实现来引用。这是一个我要从本书中学写的其中一个非常重要的好习惯。在读到【第34条】时还会对此进行进一步的展开。
缺点:
1)类如果不含有公有或者受保护的构造函数,就不能被继承。
我倒是觉得这更与【第3条】有些类似,设计一个类时,设计者是否希望这个类可被子类化(继承)或实例化,完全可以通过是否提供公有或者受保护的构造函数和构造函数的内容来控制。
某种意义上这也限制了继承的滥用,而鼓励使用复合(见【第14条】)
2)静态工厂方法和其他静态方法一样,一般要在API文档中作出特别的说明。在没有强烈的需要下,你还是应该使用规范的构造函数。
常见静态工厂方法:
用的最多的就是 getInstance()了,一般非值类的静态工厂方法都是这个,用在唯一实例化的Session性质的类,再合适不过了。
valueOf()是大多数值类所提供的,不太严格地讲,该方法返回的实力与它的参数具有同样的值。它是一个非常有效地类型转换方式。 如: String s = String.valueOf(3 * 4); // s = "12"
总结:静态工厂方法和公有构造函数各有各的好处。选择哪一个首先要基于理解。在没有充分理由的情况下,还是最好使用公有构造函数,毕竟它是语言提供的规范。
也就是说,本条的结论并不是静态工厂方法优于公有构造函数!
注:本书的第二版,可能将构造函数翻译为构造器。
我对第一版中绝大部分专有名词的翻译还是比较满意的,而且译者每每此时都把原英文单词附上了
(我印象比较深的一个个人感觉比较别扭的翻译是第35条的reflect “映像机制”,我个人更习惯于“反射”这个称呼)
【Effective Java 学习笔记】系列连载专题请见:
http://tonylian.iteye.com/categories/64208