代码之家  ›  专栏  ›  技术社区  ›  Alberto Zaccagni

具有所有类属性的构造函数还是具有setter的默认构造函数?

  •  24
  • Alberto Zaccagni  · 技术社区  · 16 年前

    以下是两种方法:

    • 具有所有类属性的构造函数

    优点:我必须输入确切数量的参数类型,因此如果我出错,编译器会警告我(顺便问一下,有没有办法防止在参数列表中错误地切换两个整数?)

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

    • setter和默认的空构造函数

    优点:我能清楚地看到我在设置什么,所以如果我做错了什么,我一输入就可以确定它(我不能使切换同一类型的两个变量的前一个错误)

    缺点:具有大量属性的对象的实例化可能需要几行代码(不知道这是否真的是一个缺点),如果我忘记设置属性,编译器什么也不会说。

    你会怎么做?为什么? 您是否知道任何光模式(考虑到每次实例化7+属性的对象时都应该使用它)来建议? 我之所以这样问是因为我不喜欢大型构造函数,因为我无法快速确定我要查找的变量在哪里,另一方面,我发现“设置所有属性”容易丢失某些属性。

    你可以自由地用利弊来论证我的假设,因为它们只是我的想法而已。)

    更新-我发现的与此相关的问题: Building big, immutable objects without using constructors having long parameter lists

    9 回复  |  直到 14 年前
        1
  •  20
  •   Rob    16 年前

    您可以查看Joshua Bloch倡导的构建器模式,并在 通用程序设计 . 有一个演示文稿的要点是 http://developers.sun.com/learning/javaoneonline/2007/pdf/TS-2689.pdf 毫无疑问,你能找到更好的参考资料。

    基本上,您还有另一个类,可能是一个内部类,它提供以所设置的属性命名的方法,并返回原始的生成器,以便您可以链接调用。它产生了相当可读的代码块。

    例如,假设我有一个 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;
        }
    
    }
    
        2
  •  26
  •   Jon Skeet    16 年前

    您已经错过了拥有一个带有大量参数的构造函数的最大优点:它允许您创建不可变的类型。

    创建不可变类型的常规方法 没有 巨大的建设者的污秽是有一个助手类型-A 建设者 它维护最终对象中需要的值,然后在准备好时构建不可变对象。

        3
  •  6
  •   Uri    16 年前

    最近关于API可用性的学术研究(CMU和Microsoft)表明,在可用性方面,使用setter的默认构造函数是可行的。 这来自Jeff Stylos和Steven Clarke的“需要对象构造函数中参数的可用性影响”,并在国际软件工程会议上发表:

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

        4
  •  3
  •   BlairHippo    16 年前

    你在文章中提到过,但我认为这是一个值得注意的重要点:除非每个输入参数都是不同的类型,否则大型构造函数的最大问题是 非常 很容易转换几个变量。编译器是一个不可靠的安全网——它会捕获一些错误,但是那些漏掉的错误将更加难以识别和调试。尤其是因为除非在另一个窗口中打开了API,否则大型构造函数的输入列表是非常不透明的。

    getter和setter非常容易调试,特别是如果对象没有正确填充,那么设置了抛出运行时异常的保护措施。我非常喜欢“易于调试”。

    在此之前,我从来没有听说过罗布提到的建设者模式。我自己从来没有用过(很明显),但这很有趣。

        5
  •  2
  •   munificent    16 年前

    出于上述不变的原因,我更喜欢使用构造函数参数。如果这给了您一个接受大量参数(比如超过四个参数)的构造函数,那么我就闻到了一股代码味道:其中一些参数应该捆绑到它们自己的类型中。

    例如,如果您有类似的内容:

    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) { ... }
    }
    

    在OOP代码库中,类太大是一个非常常见的设计问题。

        6
  •  0
  •   JRL    16 年前

    还有其他方面。如果您希望在设计时能够与您的类进行某些事情,而不是仅在运行时,例如将对象作为对象添加到对象调色板中(这是使用NETBeaS的Java),则需要提供无参数构造函数,以便能够这样做。

        7
  •  0
  •   Adam Jaskiewicz    16 年前

    这里还有其他的策略。在尝试解决如何处理大量参数之前,我认为重新访问您的设计并查看您的类是否做得太多是很重要的。看看是否可以将一些参数组合到一个新类中,并将一些行为移动到该类中。

        8
  •  0
  •   Community CDub    7 年前

    setter和默认的空构造函数

    JRL obliquely touched on it 但是考虑使用setter的一个原因是使对象符合 JavaBean specification . 这使得实例可以 editing 通过内省工具和坚持使用 serialization techniques .

        9
  •  0
  •   Michael Borgwardt    16 年前

    谁说你不能两者兼得?我会说强制属性进入构造函数,可选属性用setter处理。顺便问一句,谁说你总是需要每个属性一个setter?如果两个属性在概念上属于一起,为什么不把它们放在一起呢?

    我也喜欢构建者模式,但最重要的规则是:总是用你的大脑,找到最适合特定问题的设计。没有一刀切的解决方案。