在两者都可用的语言中,您更愿意看到实例构造函数或返回实例的静态方法吗?
例如,如果您要创建String
一个char[]
:
String.FromCharacters(chars);
new String(chars);
Jon Skeet.. 55
在Effective Java,第2版中,Joshua Bloch肯定会推荐前者.我记得有几个原因,无疑我不能:
您可以为方法指定一个有意义的名称.如果你有两种构造实例的方法,它们都采用int,但对于int有不同的含义,使用普通方法可以使调用代码更具可读性.
第一个的推论 - 您可以使用相同的参数列表使用不同的工厂方法
您可以为"潜在预期失败"情况返回null,而构造函数将始终返回值或抛出异常
您可以返回声明以外的类型(例如,返回派生类)
您可以将其用作工厂,以便可能多次返回对同一对象的引用
缺点:
它目前不是惯用语 - 开发人员更习惯于看到"新"
如果你看到"新"你知道你正在获得一个新的实例(模数我最近提到的奇怪)
您需要为子类提供适当的构造函数
在C#3中,构造函数调用能够使用对象初始化表达式以紧凑的方式设置字段/属性; 该功能不适用于静态方法调用
阅读有效Java中的第2项,可以很容易地得到Joshua Bloch赞成使用静态工厂方法作为默认选择的印象.但我认为实际情况并非如此,或者至少在2002年他与Bill Venners进行[此次采访](http://www.artima.com/intv/bloch14.html)时引用的情况并非如此在我的答案中进一步向下. (2认同)
Robert Rossn.. 22
我在创建实例时没有副作用编写构造函数,即构造函数正在做的唯一事情就是初始化属性.我编写一个静态方法(并使构造函数成为私有),如果创建实例做了一些你通常不希望构造函数做的事情.
例如:
public class Foo { private Foo() { } private static ListFooList = new List (); public static Foo CreateFoo() { Foo f = new Foo(); FooList.Add(f); return f; } }
因为我坚持这个惯例,如果我看到
Foo f = Foo.CreateFoo(); Bar b = new Bar();
在阅读我的代码时,我对这两行中的每一行都有着截然不同的期望.那段代码并没有告诉我创建一个Foo与创建一个Bar有什么不同,但它告诉我我需要看一下.
在Effective Java,第2版中,Joshua Bloch肯定会推荐前者.我记得有几个原因,无疑我不能:
您可以为方法指定一个有意义的名称.如果你有两种构造实例的方法,它们都采用int,但对于int有不同的含义,使用普通方法可以使调用代码更具可读性.
第一个的推论 - 您可以使用相同的参数列表使用不同的工厂方法
您可以为"潜在预期失败"情况返回null,而构造函数将始终返回值或抛出异常
您可以返回声明以外的类型(例如,返回派生类)
您可以将其用作工厂,以便可能多次返回对同一对象的引用
缺点:
它目前不是惯用语 - 开发人员更习惯于看到"新"
如果你看到"新"你知道你正在获得一个新的实例(模数我最近提到的奇怪)
您需要为子类提供适当的构造函数
在C#3中,构造函数调用能够使用对象初始化表达式以紧凑的方式设置字段/属性; 该功能不适用于静态方法调用
我在创建实例时没有副作用编写构造函数,即构造函数正在做的唯一事情就是初始化属性.我编写一个静态方法(并使构造函数成为私有),如果创建实例做了一些你通常不希望构造函数做的事情.
例如:
public class Foo { private Foo() { } private static ListFooList = new List (); public static Foo CreateFoo() { Foo f = new Foo(); FooList.Add(f); return f; } }
因为我坚持这个惯例,如果我看到
Foo f = Foo.CreateFoo(); Bar b = new Bar();
在阅读我的代码时,我对这两行中的每一行都有着截然不同的期望.那段代码并没有告诉我创建一个Foo与创建一个Bar有什么不同,但它告诉我我需要看一下.
我最近一直在研究一个公共API,我一直在为静态工厂方法与构造函数的选择而苦恼.静态工厂方法在某些情况下肯定是有意义的,但在其他情况下它并不是那么清楚,我不确定与API其余部分的一致性是否足以将它们包含在构造函数中.
无论如何,我从Bill-Venners采访Josh Bloch时得到了一个引用,我发现它很有用:
当你编写一个类时,你可以在我的书中列出静态工厂优于公共构造函数的优点.如果您发现在您的案例中实际应用了大量优势,那么您应该选择静态工厂.否则你应该去构造函数.
有些人对我的书中的建议感到失望.他们阅读并说:"你们对公共静态工厂如此强烈争论,我们应该默认使用它们." 我认为这样做的唯一真正缺点是,对于习惯使用构造函数创建对象的人来说,这有点令人不安.而且我认为它在程序中提供了一点点视觉提示.(您没有看到new关键字.)此外,在文档中找到静态工厂要困难得多,因为Javadoc将所有构造函数组合在一起.但我会说每个人都应该一直考虑静态工厂,并在适当的时候使用它们.
阅读了那篇引文,以及Uri提到的研究*,除非有令人信服的理由,否则我倾向于偏向于建设者.我认为没有正当理由的静态工厂方法可能只是不必要的复杂性和过度工程.虽然明天我可能会再次改变主意...
*不幸的是,这项研究更少关注静态工厂方法,而更多关注工厂模式(存在单独的工厂对象以创建新实例),因此我不确定是否可以得出静态工厂方法使许多程序员感到困惑的结论.虽然这项研究确实给我的印象是他们经常这样做.
如果您的对象是不可变的,您可以使用静态方法返回缓存的对象并节省内存分配和处理.
ICSE'07的论文研究了构造函数与工厂模式的可用性.虽然我更喜欢工厂模式,但研究表明开发人员在寻找正确的工厂方法方面较慢.
http://www.cs.cmu.edu/~NatProg/papers/Ellis2007FactoryUsability.pdf