Creé un registro de Java y me gustaría tener un constructor que admita un número reducido de argumentos en comparación con el constructor predeterminado, y calcule e inicialice todos los miembros en función de los argumentos proporcionados.
Sin embargo, encontré esto difícil de lograr dado que la primera línea del constructor personalizado debe llamar al constructor predeterminado. Mi enfoque actual es llamar a mis funciones de cálculo según sea necesario, pero esto da como resultado un procesamiento innecesario.
Seguramente debe haber una mejor manera de lograr esto?
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; } }Una solución alternativa es agregar un método de fábrica estático a su registro en lugar de un constructor adicional.
Por ejemplo:
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; } }Usar un método de fábrica estático es una solución, pero su API comienza a complicarse.
No es posible disminuir la visibilidad del constructor de registros predeterminado por diseño ( https://stackoverflow.com/a/67627794/4425643 ), por lo que usar una clase de fábrica externa también sería complicado.
En su caso, sería mejor si usara una clase regular para tener la opción de tener múltiples constructores independientes.
La primera declaración del constructor debe ser una invocación del constructor, pero no tiene que ser el constructor canónico. Esto permite construir una cadena que termina en el constructor canónico, pero introduce variables locales (parámetros) en el medio para evitar cálculos redundantes:
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; } }Pero podría ser preferible usar un método de fábrica, como lo sugiere esta respuesta . La ventaja es que el método de fábrica puede tener un nombre aclaratorio. P.ej
public static MyRecord fromA(double a) { …que incluso permite tener, por ejemplo
public static MyRecord fromB(double b) { …en la misma clase. La sobrecarga de constructores, por otro lado, requiere más cuidado. Solo debe usarse cuando se espera que sea obvio para los usuarios de la clase qué parámetros se han omitido y de qué manera se generarán a partir de los valores dados.