【问题标题】:Field initialization in class constructors: direct or through "setter"?类构造函数中的字段初始化:直接还是通过“setter”?
【发布时间】:2011-06-24 01:11:09
【问题描述】:

在使用 C++ 和 C# 一段时间后,我正在开发一个 Java 项目,但我对构造函数中字段初始化的最佳实践存有疑问。基本上,假设我有一个简单的 Point 类。在 C++ 中,我在构造函数中的字段初始化如下所示:

class Point {
public:
    // Default constructor
    Point(double x, double y) : x(x), y(Y) { }

protected:
   // Coordinates
   double x, y;
};

在 C# 中 ...

class Point {
    // Coordinates, with automatic properties
    public double X { get; protected set; }
    public double Y { get; protected set; }

    // Default constructor
    Point(double x, double y) {
        X = x;
        Y = y;
    }    
}

在 Java 中...最佳实践建议为必须从外部访问的字段定义 getter / setter。但建议在课堂内也使用它们吗?疑问来自这样一个事实,即 Eclipse 似乎很乐意将类代码中的每个 this.field = field 转换为具有 getter/setter 的字段的 setField(field),即使我从类代码内部读取/写入(因此我不会需要使用类接口)。

这基本上为每次访问添加了一个函数调用。现在,除了设置字段涉及一些其他操作(即验证、处理等)的情况之外,这还有什么意义吗?常识会建议使用getter / setter类似于使用C#属性,但这里我特别质疑C#的自动属性,它只涉及基本访问,没有任何处理。所以问题是:在类代码内部调用 getter / setter 有什么好处吗?

谢谢
图努兹

【问题讨论】:

    标签: java oop constructor initialization field


    【解决方案1】:

    Getters Setters 封装了事物。今天没有什么要处理的,但明天你可能需要处理一些事情。所以最好使用 Getters Setters。

    对于默认值初始化,您可以使用构造函数。\ 但如果在设置获取时有一些处理,请使用 Getters Setters。

    最佳实践是使用

    • 构造函数/初始化块将成员字段初始化为其值。
    • 直接从类访问字段内部
    • 从外部类使用 getter/setter

    另见

    【讨论】:

    • “明天你可能需要”是不是有点为时过早?
    【解决方案2】:

    我也更喜欢直接访问。但是,对于非平凡的 get/setter,如果内部也需要非平凡的语义,您可能希望使用它们。

    如果您事先不知道 get/setter 将是非平凡的,那么您也可能事先不知道内部是否也应该执行额外的工作,所以过早封装不是看起来很有用。

    我的 Eclipse (Helios) 安装不执行此转换,因此我假设您可以将其关闭。

    【讨论】:

      【解决方案3】:

      如果您要对要设置的值进行验证、格式化或处理,建议使用 setter。

      假设你需要你的类 Foo 总是需要有一个非空的 bar 值,当不使用 setter 时,你需要在每次设置值时重写验证代码:

      public class Foo {
      
         private String bar;
      
         public Foo(String aValue) {
      
            if(aValue==null || aValue.equals("")) {
                throw new IllegalArgumentException("Duh");
            }
      
            bar=aValue;
      
         }
      
         public void setBar(String aValue) {
      
            if(aValue==null || aValue.equals("")) {
                throw new IllegalArgumentException("Duh");
            }
      
            bar=aValue;
      
         }
      }
      

      使用 setter,您可以重用代码,并允许在一个点上实现更多逻辑:

      public class Foo {
      
         private String bar;
      
         public Foo(String aValue) {
      
            setBar(aValue);
      
         }
      
         public void setBar(String aValue) {
      
            if(aValue==null || aValue.equals("")) {
                throw new IllegalArgumentException("Empty values not allowed");
            }
      
            if(aValue.length()>24) {
                 throw new IllegalArgumentException("Too long");
            }
            bar=aValue;
      
         }
      
      }
      

      【讨论】:

        【解决方案4】:

        正如我所学到的,在构造函数中使用 getter 和 setter 是不必要的,只会创建额外的方法调用来减慢程序的速度。我不确定这有多重要,因为此类方法调用通常在编译时内联。

        【讨论】:

          猜你喜欢
          • 2020-10-29
          • 2018-05-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-04-11
          相关资源
          最近更新 更多