【问题标题】:Preferred way of declaring methods in a class在类中声明方法的首选方式
【发布时间】:2011-08-31 15:32:38
【问题描述】:

我对在类中创建用于设置信息的方法有疑问。

  1. 为设置每个属性创建单独的方法

    class Address{
        private String name;
        private String city;
    
        public setName(String name) { ... }
        public setCity(String name) { ... }
    }
    
  2. 创建设置所有属性的单一方法

    class Address{
        private String name;
        private String city;
    
        public setAddress(String name,String city) { ... }
    }
    

从以上两种方式来看,从记忆的角度来看,哪种方式更可取?

【问题讨论】:

  • 用两种方法的代码示例向我们展示您的意思。
  • 这门课的目的是什么?它是一个价值对象吗?您需要独立设置每个值吗?创建对象后这些值是否必须更改? “记忆的观点”是什么意思?人类记忆还是计算机记忆?
  • 第一个例子很好,第二个例子不好。使用构造函数。
  • 如果你真的追求可变对象,那么 getter/setter 就可以了。然而,不可变对象越来越普遍:stackoverflow.com/questions/2848938
  • +1 语法T3rr0r。我非常同意这种观点。

标签: java coding-style


【解决方案1】:

常见的做法是使用JavaBean风格

class Address {
  private String name;
  private String city;

  public setName(String name){
    this.name = name;
  }

  public String getName() {
     return name;
  }

  public setCity(String city){
     this.city = city;
  }

  public getCity() {
    return city;
  }

}

另一个与你的第二种方法非常相似的常见做法是创建不可变对象。参数被传递给构造函数而不是大的setter方法。

class Address {
  private final String name;
  private final String city;

  public Address(String name, String city) {
      this.name = name;
      this.city = city;
  }

  public String getName() {
     return name;
  }

  public getCity() {
    return city;
  }
}

从内存的角度来看,不同之处在于第二个示例是在构造函数中设置所有属性,并且所有这些属性都是不可变的。一般来说,以这种方式构造的对象在多线程使用时更安全。

在第二个示例中,不需要同步。当多个线程使用标准 JavaBean 对象时,您需要处理同步/内存问题。

【讨论】:

    【解决方案2】:

    我看不出这两种方法在记忆方面会有什么不同。

    选择在类接口中最有意义的方法。

    我建议仅当两个属性在逻辑上密切相关,或者如果存在您不想暂时中断(甚至暂时)的某些类不变量时,才使用方法 2。

    在您的Address 示例中,我肯定会使用两个setter 方法,因为在谈论地址时,名称和城市是完全无关的。


    对于一般的方法,我想说的是,无论您是否将一个方法一分为二,对内存消耗的影响都很小。每个对象都没有分配自己的一组方法。包含方法的内存在类的所有实例之间共享。


    经验法则:努力使您的班级界面干净且合乎逻辑。

    【讨论】:

      【解决方案3】:

      为什么不使用方法#2

      不推荐您的第二个示例,因为如果您向 Address 类添加了一个新字段,那么您是将其添加到现有的 setter 方法中还是创建一个新的 setter 方法?如果将它添加到现有的 setter 方法中,那么任何调用该方法的类都会被破坏。如果您创建了一个新的 setter 方法,那么任何想要使用该类的人都会感到困惑,为什么某些字段以这种方式分组在一起而其他字段却不是。

      对您希望公开的每个字段使用单独的 setter 方法

      通常的做法是为您希望公开的类中的每个字段(即您的第一个示例)设置一个 setter 方法。这是否是一个好的做法值得商榷,因为它强制一个类为mutable.。如果可能,最好使一个对象不可变,for a number of reasons

      使用构造函数初始化字段

      使类不可变的一种方法是摆脱 setter 方法,而是通过类构造函数使字段可设置,如下所示。以这种方式实现它的缺点是,如果你的类有很多字段,它可能会导致大型的、不可读的构造函数调用。

      public class Address {
          public String name;
          public String city;
      
          private Address(String name, String city) {
              this.name = name;
              this.city = city;
          }
      }
      

      使用 Builder 模式初始化您的字段

      下面是一个完全替代的实现(受this article 启发),它是Builder 模式的变体。它在不牺牲可读性的情况下模拟对象可变性。

      public class Address {
          public String name;
          public String city;
      
          private Address() {}
      
          private void setName(String name) {
              this.name = name;
          }
      
          private void setCity(String city) {
              this.city = city;
          }
      
          static class Builder {
              private Address address = new Address();
      
              public Builder name(String name) {
                  address.setName(name);
                  return this;
              }
      
              public Builder city(String city) {
                  address.setCity(city);
                  return this;
              }
      
              public Address build() {
                  return address;
              }
          }
      }
      

      使用上述类,您可以创建 Address 类的不可变实例,如下所示:

      Address address = new Address.Builder()
              .name("Mansoor's address")
              .city("Toronto")
              .build();
      

      哪种方法使用更多内存?

      从内存的角度来看,应该没有任何区别,因为内存中类的大小取决于类中的字段。由于所有三个实现都具有相同的字段,因此无论您使用哪种方法,它们都应该占用相同的内存空间。

      【讨论】:

      • 这确实意味着我只要求设置方法..告诉我任何方法
      • 在我的回答中评论了“一般方法”方面。
      • 我不同意你的回答。为什么每个字段都有设置器是常见的做法?很多时候,一个类中有一个不想公开的内部字段。我所知道的唯一常见做法是在 bean 中。
      • @Farmor 只对 Java bean 成为一种常见做法是有意义的,但许多非 bean 类使用 setter 而不是构造函数参数。只需看一下常用的 Spring API(例如 org.springframework.jdbc.core.JdbcTemplate)。 Spring 在很大程度上也基于在非 POJO 上设置 setter。
      • 当然,您可能严重依赖非 POJO 上的 setter类。
      【解决方案4】:

      这不是一个明确的问题。你的意思是,你宁愿有setFoo(String)setBar(int)这样的两种方法,还是setFooBar(String, int)这样的一种方法?这实际上取决于这些是否是逻辑上不同的属性,在这种情况下您需要单独的方法,或者是否经常(或仅)将它们设置在一起有意义。你可以同时提供。

      对内存没有任何影响,没有。

      【讨论】:

        【解决方案5】:

        JavaBean 标准是为每个属性设置 getter 和 setter:http://en.wikibooks.org/wiki/Java_Programming/Java_Beans。如果您不想遵循该标准约定,那么它对您的商店最有意义。根据此线程上的其他答案,可能存在最小的内存增量(如果有)。

        【讨论】:

          【解决方案6】:

          Nb.1 毫无疑问。

          而且你不用手写代码,只声明你的字段。

          然后您让 Eclipse 为您完成其余的工作。

          在 Eclipse 中使用 Source --> 生成 getter 和 setter。

          在对象构造函数中完成了与 #2 非常相似的构造。

          关于记忆的更新问题。在生产代码中不必担心这两种方式之间的内存差异。

          【讨论】:

          • 数字 1 是常见的做法,但它强制类是可变的。
          • 你这是什么意思? setAddress("London", "Uk") 和 [setName("Uk") setCity("London")] 不是同样可变的吗?
          • 他们会——这两种方法都不是我要说的。 :)
          【解决方案7】:

          您通常为每个属性编写一个 setter 和一个 getter 方法。

          我并没有真正看到一种方法足以设置所有属性的情况。在这种情况下,所有属性都应该具有相同的值吗?或者您总是必须为所有属性传递参数。这两种情况都不是你想要的。所以你显然应该更喜欢你的第一种方法。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-12-09
            • 2018-01-29
            • 1970-01-01
            • 2014-02-02
            • 1970-01-01
            相关资源
            最近更新 更多