在两者都可用的语言中,您更愿意看到实例构造函数或返回实例的静态方法吗?
例如,如果您要从String
创建char[]
:
String.FromCharacters(chars);
new String(chars);
答案 0 :(得分:53)
在Effective Java, 2nd edition中,Joshua Bloch肯定会推荐前者。我记得有几个原因,无疑有些原因我不能:
缺点:
答案 1 :(得分:21)
我在创建实例时没有副作用编写构造函数,即构造函数正在做的唯一事情就是初始化属性。我编写一个静态方法(并使构造函数成为私有)如果创建实例会执行一些您通常不希望构造函数执行的操作。
例如:
public class Foo
{
private Foo() { }
private static List<Foo> FooList = new List<Foo>();
public static Foo CreateFoo()
{
Foo f = new Foo();
FooList.Add(f);
return f;
}
}
因为我遵守这个惯例,如果我看到
Foo f = Foo.CreateFoo();
Bar b = new Bar();
在阅读我的代码时,我对这两行中的每一行都有着截然不同的期望。该代码并没有告诉我创建一个Foo与创建一个Bar有什么不同,但它告诉我需要看看。
答案 2 :(得分:10)
我最近一直在研究一个公共API,我一直在为静态工厂方法与构造函数的选择而苦恼。静态工厂方法在某些情况下肯定是有意义的,但在其他情况下它并不是那么清楚,我不确定与API其余部分的一致性是否足以将它们包含在构造函数中。
无论如何,我遇到了quote from a Bill-Venners interview with Josh Bloch,我发现它很有用:
当你上课时,你可以 记下我的书的清单 静态工厂的优势超过 公共建设者。如果你找到了 其中很多 优势实际适用于您的 案件,然后你应该去 静态工厂。否则你应该 和建设者一起去。
有些人对此感到失望 我书中的建议。他们看了 并说,“你们如此强烈地争论 对于我们公共静态工厂 应该默认使用它们。“我 认为唯一真正的劣势 这样做是因为它有点 对使用过的人不满 使用构造函数来创建他们的 对象。而且我想它提供了一个 少了一点视觉线索 程序。 (你没有看到新的 关键字。)还有一点 很难找到静态工厂 文档,因为Javadoc 将所有构造函数组合在一起。 但我会说每个人都应该这样做 考虑所有的静态工厂 时间,并在它们存在时使用它们 合适的。
阅读了这句话后,the study that Uri mentioned *,除非有令人信服的理由,否则我倾向于偏向建造者。我认为没有正当理由的静态工厂方法可能只是不必要的复杂性和过度工程。虽然明天我可能会再次改变主意......
*不幸的是,这项研究更少关注静态工厂方法,而更多地关注工厂模式(存在单独的工厂对象以创建新实例),所以我不确定是否可以得出静态工厂方法混淆许多的结论程序员。虽然这项研究确实给我的印象是他们经常会这样做。
答案 3 :(得分:9)
如果您的对象是不可变的,您可以使用静态方法返回缓存的对象并节省内存分配和处理。
答案 4 :(得分:7)
来自ICSE'07的论文研究了构造函数与工厂模式的可用性。虽然我更喜欢工厂模式,但研究表明开发人员在找到正确的工厂方法时速度较慢。
http://www.cs.cmu.edu/~NatProg/papers/Ellis2007FactoryUsability.pdf
答案 5 :(得分:2)
静态方法。然后你可以返回一个null,而不是抛出异常(除非引用类型)
答案 6 :(得分:2)
我更喜欢实例构造函数,因为这对我来说更有意义,并且与您尝试表达的内容相比,潜在的模糊性更少(即:如果FromCharacters是一个采用单个字符的方法,那该怎么办)。当然,这肯定是主观的。
答案 7 :(得分:2)
我个人更喜欢看普通的构造函数,因为构造函数应该用于构造。但是,如果有充分的理由不使用一个,即如果FromCharacters明确声明它没有分配新的内存,那将是值得的。调用中的“新”具有意义。
答案 8 :(得分:2)
这取决于。对于使用实例构造函数是“正常”的语言,我通常会使用一个,除非我有充分的理由不这样做。这符合最不意外的原则。
顺便说一句,你忘了另一个常见的情况:null / default构造函数与初始化方法配对。
答案 9 :(得分:1)
正如Jon Skeet对Josh Bloch的解释一样,在许多情况下,静态工厂方法比构造函数更可取的原因有很多。我会说,如果这个类是一个简单的类,没有昂贵的设置或复杂的用法,请继续使用惯用的构造函数。现代JVM使对象创建极其快速且便宜。如果类可能是子类,或者你可以使它成为不可变的(并发编程的一大优势,这只会变得更加重要),那么请使用工厂方法。
还有一个提示。请勿命名工厂方法Foo.new*
或Foo.create*
。具有这些名称的方法应始终返回一个新实例,这样做会错过工厂方法的一大优点。更好的命名约定是Foo.of*
或Foo.for*
。 Google Guava library(以前的 Google Collections Library )在这方面做得很好,imho。
答案 10 :(得分:0)
当然,与构造函数相比,静态工厂方法有很多优点。
getInstance()
。