【问题标题】:Calculate members during construction in records在记录中计算施工期间的成员
【发布时间】:2022-03-15 17:15:47
【问题描述】:

我创建了一个 Java record,并希望有一个构造函数,与默认构造函数相比,它接受的参数数量减少,并根据给定的参数计算和初始化所有成员。

但是,鉴于自定义构造函数的第一行必须调用默认构造函数,我发现这很难实现。我目前的做法是根据需要调用我的计算函数,但这会导致不必要的处理。

肯定有更好的方法来实现这一点吗?

public record MyRecord(double a, double b, double c) {
     public MyRecord(double a) {
          this(a, calculateB(a), calculateC(a, calculateB(a)));
     }

     private static double calculateB(double a) {
          // Some calculations 
          return b;

     }

     private static double calculateC(double a, double b) {
          // Some calculations 
          return c;
     }
}

【问题讨论】:

  • 我非常喜欢在对象中只使用 null 构造函数并使用 setter 来避免这种情况
  • @ControlAltDel 这个问题是关于记录的,记录是不可变的。

标签: java record


【解决方案1】:

另一种解决方案是将静态工厂方法添加到您的记录中,而不是额外的构造函数。

例如:

public record MyRecord(double a, double b, double c) {

    public static MyRecord newMyRecord(double a) {
        var b = calculateB(a);
        var c = calculateC(a, b);
        return new MyRecord(a, b, c);
    }


    private static double calculateB(double a) {
        // Some calculations 
        return b;

    }

    private static double calculateC(double a, double b) {
        // Some calculations 
        return c;
    }
}

【讨论】:

    【解决方案2】:

    构造函数的第一条语句必须是构造函数调用,但不一定是规范的构造函数。这允许构造一个以规范构造函数结束的链,但在中间引入局部变量(参数)以避免冗余计算:

    public record MyRecord(double a, double b, double c) {
         public MyRecord(double a) {
              this(a, calculateB(a));
         }
    
         private MyRecord(double a, double b) {
              this(a, b, calculateC(a, b));
         }
    
         private static double calculateB(double a) {
              // Some calculations 
              return b;
         }
    
         private static double calculateC(double a, double b) {
              // Some calculations 
              return c;
         }
    }
    

    但使用工厂方法,如this answer 建议的那样,可能更可取。优点是工厂方法可以有一个明确的名称。例如

    public static MyRecord fromA(double a) {
    …
    

    甚至允许拥有,例如

    public static MyRecord fromB(double b) {
    …
    

    在同一个班级。另一方面,重载构造函数需要更加小心。仅当期望类的用户清楚哪些参数已被省略以及它们将从给定值生成的方式时,才应使用它。

    【讨论】:

      【解决方案3】:

      使用静态工厂方法是一种解决方案,但您的 API 开始变得混乱。

      不可能通过设计来减少默认记录构造函数的可见性 (https://stackoverflow.com/a/67627794/4425643),因此使用外部工厂类也会很麻烦。

      在您的情况下,最好使用常规类来获得拥有多个独立构造函数的选项。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-17
        相关资源
        最近更新 更多