【问题标题】:Assigning a number of fields via setter or constructor通过 setter 或构造函数分配多个字段
【发布时间】:2014-11-26 13:21:58
【问题描述】:

我研究了这个主题,发现通过构造函数分配字段是一种更好的做法,而不是 setter。但是,如果我有一个包含 10 个字段的对象怎么办?这将导致大型构造函数,这仍然被认为是好的做法吗?

例如:

   public DefaultAccount(Long id, String name, String surname, String username, String password, Role role) {
    this.id = id;
    this.name = name;
    this.surname = surname;
    this.username = username;
    this.password = password;
    this.role = role;
   }

这个构造函数对我来说看起来很大。

【问题讨论】:

  • 这不是坏习惯。你的构造函数没有那么大,因为它不包含智能。
  • 如果我的构造函数有两倍的字段怎么办?那还是正常的吗?
  • 构造函数可以分配所有字段。如果您发现单个类具有这么多字段是正常的(并且可以是正常的),您可以拥有一个分配所有字段的构造函数。但是你应该有另一个参数更少的构造函数......
  • 我还发布了此类问题,但由于他们说答案将基于意见,因此被否决了。在这种情况下,有些人可能也会这样认为,但我不这样认为:)。来自我的 +1!
  • @chsdk 这不是完全一样的问题!这里是关于大小而不是何时使用构造函数的原则。

标签: java constructor field setter


【解决方案1】:

带有多个参数的构造函数(或具有多个带有不同参数集的构造函数)的一个问题是当多个参数具有相同类型时可能发生的错误。从您的示例中考虑,以错误的方式获取姓名和姓氏的顺序是多么容易。

解决方案可能是使用 Builder 模式。

以下是对其工作原理的全面介绍:the builder pattern in practice 以下堆栈溢出问题也很好地涵盖了它:when would you use the builder pattern

【讨论】:

    【解决方案2】:

    在我看来,这取决于情况。您列出的示例是一个非常简单的类,只有简单的类型。我会认为这没问题。但是,我不太确定您考虑到二传手的说法。但是您可能需要考虑一些事情:

    如果您正在使用一些更大的框架(Spring、Hibernate...),其中很多会使用默认构造函数(如 new Person())实例化对象,然后为字段调用 setter。如果某些东西不可用,它们会抛出异常。

    拥有像您列出的那样的构造函数很好。但是无论如何都需要二传手。如果它们变得复杂,请考虑重构该类。也许需要太多的依赖。也许您可以将它们封装在另一个对象(例如配置)中,而不是拥有 10 个参数。

    尽量不要公开字段。当你必须在 setter 中检查某个条件并且你的字段是公开的时,你会花一些时间来重构它。如果需要,检查 setter 中的先决条件并抛出异常。

    我还在 stackoverflow 上找到了这个问题,这让关于 setter 的问题更进一步:Java setting private fields inside constructors

    【讨论】:

      【解决方案3】:

      实际上在任何方法(包括构造函数)中都有大量参数是一种不好的做法。

      首先,我看到 DefaultAccount 构造函数的字段与 Account 没有直接关系。

      您应该将例如姓名和姓氏提取到另一个(用户?)类等等。

      【讨论】:

        【解决方案4】:

        如果不是所有参数都是强制性的,那么请考虑使用 Joshua Bloch 在 Effective Java 的 Item #2 中建议的 Builder 模式,它说...

        客户端不是直接生成所需的对象,而是调用 具有所有必需参数的构造函数(或静态工厂) 并获得一个 builder 对象。然后客户端调用类似setter的方法 在构建器对象上设置每个感兴趣的可选参数。 最后,客户端调用无参数的build方法生成 对象,它是不可变的。

        【讨论】:

          【解决方案5】:

          在我看来,最有效的方法是将问题分解为尽可能多的类,如下所示:

          public DefaultAccount(Long id, String name, String surname, User user) 
          {
              this.id = id;
              this.name = name;
              this.surname = surname;
              this.user = user;
          }
          
          // From second class User
          public User(String username, String password, Role role)
          {
              this.username = username;
              this.password = password;
              this.role = role;
          }
          

          这样可以避免大量的构造函数并提高代码的可维护性和可读性。

          您也可以像here 中描述的那样使用配置类

          【讨论】:

            【解决方案6】:

            当你有多个类时使用 getter 和 setter,当你的字段是私有的(或受保护并且需要从另一个包访问)时也是如此。 如果您只有一个类,则不需要创建 getter 和 setter,您可以直接将值分配给对象(假设您不想在构造函数中分配它们)

            【讨论】:

              猜你喜欢
              • 2018-03-26
              • 2014-09-26
              • 2011-06-24
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-01-27
              • 2014-02-01
              相关资源
              最近更新 更多