2009-05-06 139 views
24

以下是两种方法:具有所有类属性的构造函数或具有setter的默认构造函数?

  • 构造与所有的类属性

优点:我必须把类型的参数,一个确切的数字,所以如果我使编译器警告我的错误(顺便说一下,有没有办法来防止在参数列表中错误地切换两个整数的问题?)

缺点:如果我有很多属性,实例化行可能变得非常长,它可能跨越两个或更多行

  • setter和默认的空构造

优点:我可以清楚地看到什么我设置的,所以如果我做错了,我可以尽快找出它作为我打字它(我不能使交换同一类型的两个变量的previuos错误)缺点:具有许多属性的对象的实例可能需要几行(不知道这是否真的是一个con),并且如果我忘了设置一个属性,编译器没有说什么。

你会做什么,为什么? 你是否知道任何光线模式(考虑到它应该在每次有7+个属性被实例化的对象时使用)来建议? 我在问这个,因为我倾向于不喜欢大的构造函数,我无法快速找出变量,我正在寻找,另一方面,我发现“设置所有属性”容易丢失一些属性。

随意的说法我在利弊的假设,因为它们只属于我的想法:)

更新 - 我发现一个问题,这是关系到这一点:你已经错过了Building big, immutable objects without using constructors having long parameter lists

回答

20

您可以看看Joshua Bloch倡导的Builder模式,并在Effective Java中描述。在http://developers.sun.com/learning/javaoneonline/2007/pdf/TS-2689.pdf上有主要观点的介绍;毫无疑问,你可以挖掘更好的参考。

基本上,你有另一个类,可能是一个内部类,它提供了在属性被设置后命名的方法,以及返回原始构建器的方法,以便连接调用。它使相当可读的代码块。

例如,让我们假设我有一个简单的Message与几个属性。客户端代码构建这可以使用生成器来准备Message如下:

Message message = new Message.Builder() 
    .sender(new User(...)) 
    .recipient(new User(...)) 
    .subject("Hello, world!") 
    .text(messageText) 
    .build(); 

Message.Builder片段可能类似于以下内容:

public class Builder { 

    private User sender = null; 
    // Other properties 

    public Builder sender(User sender) { 
     this.sender = sender; 
     return this; 
    } 
    // Methods for other properties 

    public Message build() { 
     Message message = new Message(); 
     message.setSender(sender); 
     // Set the other properties 
     return message; 
    } 

} 
26

最大的职业有一个构造函数负载的参数:它可以让你创建不可变的类型。

创造稳定的类型没有巨大构造龌龊的方式,一般是有一个辅助型 - 一个建设者它保持你想在你的最终目标值,然后建立的时候你是不可变对象准备。

+0

无论如何,建设者是不是更好的策略? – Uri 2009-05-06 17:09:08

+0

此外,如果您的对象的状态无法在未设置属性的情况下运行,则强制用户通过构造函数设置它们。 – 2009-05-06 17:09:14

+0

@Uri:如果你只有几个属性,生成器模式已经超过了顶级IMO。 – 2009-05-06 17:18:02

6

最近关于API可用性的学术研究(CMU和Microsoft)表明,使用setter的默认构造函数将成为可用性方式。 这是从“要在对象构造参数的可用性影响”,杰夫STYLOS和史蒂芬·克拉克,并在国际软件工程大会提出:

Abstract: 的API的可用性越来越重要的是程序员的工作效率。基于对特定API的可用性研究的经验,研究了用于研究许多API的常见设计选择的可用性的技术。进行比较研究以评估专业程序员如何在对象的构造函数中使用具有所需参数的API,而不是无参数“默认”构造函数。据推测,通过引导程序员正确使用对象并防止错误,所需的参数将创建更多可用的自编档API。然而,在研究中发现,与预期相反,程序员强烈倾向于使用不需要构造函数参数的API,并且更加有效。使用认知维度框架分析参与者的行为,并揭示所需的构造参数干扰常见的学习策略,导致不期望的过早承诺。

0

还有其他方面。如果您希望在设计时能够在设计时为您的类提供某些功能,而不仅仅是在运行时,例如在Object Palette中添加类作为对象(这是使用Netbeans的Java),您需要提供一个无参数构造函数为了能够这样做。

3

你在你的文章中提到它,但我认为这是一个值得更多关注的重要观点:除非每个输入参数都是不同的类型,否则大型构造函数的大问题是它很容易转换一对的变量。编译器是一个不可靠的安全网络 - 它会发现一些错误,但是那些经历过的错误将会更难以识别和调试。特别是因为巨大构造函数的输入列表非常不透明,除非您在另一个窗口中打开了API。

获取器和设置器非常容易调试,尤其是如果您设置的保护措施在对象未正确填充时会抛出运行时异常。我是“易于调试”的狂热粉丝。

在此线程之前,我从来没有听说过Builder模式Rob提到过。从来没有使用它(显然),但它是有趣的。

0

这里还有其他策略。在试图弄清楚如何处理很多参数之前,我认为重新访问您的设计并查看您的班级是否做得太多非常重要。看看你是否可以将一些参数组合到一个新的类中,并将某些行为转移到该类中。

2

为了上述不可变性的原因,我更喜欢采用构造函数参数。如果这给了你一个需要大量参数的构造函数(比如说超过四个),那么这对我来说就是一种代码嗅觉:其中一些参数应该被捆绑到它们自己的类型中。

例如,如果你有这样的事情:

class Contact 
{ 
    public Contact(string firstName, string lastName, string phoneNumber, 
     string street, string city, string state, int zipCode) { ... } 
} 

我想它重构为:

class Contact 
{ 
    public Contact(Person person, PhoneNumber number, Address address) { ... } 
} 

class Person 
{ 
    public Person(string firstName, string lastName) { ... } 
} 

class PhoneNumber 
{ 
    public PhoneNumber(string digits) { ... } 
} 

class Address 
{ 
    public Address(string street, string city, string state, int zipCode) { ... } 
} 

过大的班是面向对象的代码库,非常常见的设计问题。

0

谁说你不能同时做?我会说必须的属性进入构造函数,可选的是用setter处理。顺便说一句,谁说你每个物业都需要一个二传手?如果两个属性在概念上属于一起,为什么不把它们放在一起?

我也喜欢Builder模式,但最重要的规则是:始终使用您的大脑并找到最适合特定问题的设计。没有一种万能的解决方案。

相关问题