¿Constructores automáticos / creadores de cadenas para Java?

7

Considera ese código:

FancyClass c = new FancyClass();
s.setParameter(value);
s.setParameter2(value2);
//a lot of parameters

Es realmente ingenuo, así que podemos usar un patrón de construcción:

FancyClass c = new FancyClassBuilder().setParameter(value).setParameter2(value2).build()

Está bien, pero ¿qué pasa si tenemos que usar muchos configuradores durante un programa?

s.setParameter(value)
s.setParameter1(value)
s.setParameter2(value)
s.setParameter3(value)
//more and more...

Será más eficiente y menos hervido:

s.setParameter(value).setParameter1(value).setParameter2(value)
 .setParameter3(value)

Parece más bien y le permite al programador no hacer esta acción: (lo odio):

s.setParamter()
// a lot of doing smth
s.setParameter2()

Incluso no es necesario guardar estos setters (porque es un problema heredado, alguien simplemente pulsa enter dos veces y alguien escribe otro código ...

¿Qué pasa si ...

@SetterChain
class MyFancyClass {
  public void setParameter(Parameter p) {}
  public Parameter getParameter(Parameter p) {}
  public void setParameter2(Parameter p) {}
  public Parameter getParameter2(Parameter p) {}
}

//somewhere else...

MyFancyClass s = new MyFancyClass()

//a long time ago

s.set().parameter(value).parameter2(value); //and more and more...

¿Cosas geniales o no? ¿Esta solución aumentaría significativamente la calidad del código o no y es un desastre y por qué?

    
pregunta Dawid Pura 24.04.2015 - 15:37

4 respuestas

3

El patrón del Generador aborda un problema particular que surge: los constructores con una docena (¡o más!) de argumentos. Sí, a menudo hay otro problema al acecho con tales objetos, pero el Generador hace que uno no necesite demasiados constructores para manejar todas las diferentes variaciones sobre cómo se puede construir el objeto.

Un establecedor de estilo fluido (donde el definidor devuelve this ), no tiene este problema. Aparte de algunas molestias estilísticas, no veo un problema que deba resolverse.

Tener una anotación de tiempo de compilación, mientras que limpio, fresco y poderoso agrega una cantidad significativa de complejidad a la compilación del proyecto y dificulta que alguien (o algo) lea el código para razonar al respecto. Claro, puedes anotarlo y hacer que el compilador haga su magia ... pero a menudo hay algo antes del compilador (aparte del programador) que necesita lidiar con el código.

El "algo" que lee el código es una verdadera preocupación aquí. El IDE no conoce el método set() . Tampoco sabe lo que devuelve, ni todos los métodos que it tiene. Esto haría que la vista del IDE de la clase sea una masa roja de marcadores de "esto no existe".

El enfoque set() también está lejos de ser estándar (y en realidad no resuelve un problema real) y dificulta que un nuevo codificador llegue a la base de códigos y lo entienda. Agrega complejidad innecesaria al proceso de construcción y puede hacer que el IDE sea infeliz.

Si bien todo esto puede ser genial e inteligente (sí, creo que las anotaciones son geniales e inteligentes y tengo una relación de amor / odio con ellas mismas), no creo que este sea un buen camino a seguir.

    
respondido por el user40980 24.04.2015 - 16:30
5

Si bien no es exactamente lo mismo que sugirió, ya existe algo en este sentido. Si desea proporcionar esta función a sus proyectos Java, puede considerar el uso de Lombok . Tiene un @Builder anotación , que le permite crear un constructor con casi una sola línea de código y en el al mismo tiempo evite exponer o incluso escribir colocadores.

Así es como se puede usar:

import lombok.Builder;

@Builder
public class Person {

    private String name;

    private int age;

    public String getName() { return name; }

    public int getAge() { return age; }
}

Para establecer los campos en una instancia de esta clase, ahora llamará:

Person instance = Person.builder().name("Tom").age(25).build();

De hecho, si decides usar Lombok, puedes hacer que genere los captadores para ti y hacer que el código sea aún más corto:

import lombok.Builder;
import lombok.Getter;

@Builder
public class Person {

    @Getter
    private String name;

    @Getter
    private int age;
}

Las desventajas incluyen la necesidad de configurar Lombok para su proyecto e incluir una dependencia en él. He trabajado con él en un par de proyectos y puedo decir que es relativamente sencillo cuando se trata de la configuración del entorno.

Creo que el peor inconveniente es el de las capacidades limitadas de depuración (ya que sus fuentes originales no contendrán las líneas que realmente se ejecutan).

De todos modos, está ahí para que intentes y compruebes los pros y los contras de tal solución.

Otra opción para tener este tipo de azúcar sintáctica sería cambiar a Groovy, que tiene una curva de aprendizaje bastante suave para los desarrolladores de Java y soporte muy bueno para los constructores también gracias a sus transformaciones AST .

    
respondido por el toniedzwiedz 26.04.2015 - 16:19
1

No evitaría que las personas tengan:

s.set().parameter1(value);

// yadda yadda yadda

s.set().parameter2(anotherValue);

Que es lo que frunció el ceño en primer lugar, así que diría que no aumentaría la calidad del código por sí mismo.

El patrón del generador, como usted menciona, obliga a pasar todos los valores en un lugar (o aplazar la construcción del objeto a menos que estén todos), pero eso también se puede lograr al tener un constructor que espera que todos los valores se transfieran directamente. de distancia, más inmutabilidad, por lo tanto, todos los captadores y no establecedores.

Los constructores fluidos son una especie de sintaxis de azúcar para eso, equivalentes a parámetros nombrados como: enlace

Si te refieres a generadores automáticos para clases de constructor, en lugar de clases de entidad con configuradores chainable, entonces sí existen, por ejemplo. enlace

Personalmente no veo mucho sentido utilizarlos, dado que IntelliJ Idea o Android Studio es capaz de generar automáticamente una clase de constructor en cuestión de segundos.

    
respondido por el Konrad Morawski 24.04.2015 - 16:29
0

JDK 1.8 proporciona un enfoque muy agradable (depende de su criterio) para usar Fluent Pattern, verifique este ejemplo (usando la clase Person del ejemplo aquí):

import java.util.function.Consumer;

public class Person {
   private String name;
   private String lastName;
   private int age;
   private Genre genre; // assuming enum MALE/FEMALE

   // Some GETs

   // Fluent SETTERS
   public Person setName(String name) {
      this.name = name;
      return this;
   }
   public Person setLastName(String lastName) {
      this.lastName = lastName;
      return this;
   }
   public Person setAge(int age) {
      this.age = age;
      return this;
   }
   public Person setGenre(Genre genre) {
      this.genre = genre;
      return this;
   }
   // Beautiful things start just here
   public static Person build(Consumer<Person> block) {
      Person person = new Person(); // constructor may be private :)
      block.accept(person);
      return person;
   }
}

Usando el "constructor":

public class JDK8ConsumerExample {
   public static void main(String ... args) {
      Person person = Person.build(p ->
         p.setNane("Jhon")
          .setLastName("Doe")
          .setAge(40)
          .setGenre(Genre.MALE)
        );
   }
}

Un tutorial muy bueno de Mr. Venkat Subramaniam aquí

    
respondido por el Vielinko 05.04.2017 - 20:47

Lea otras preguntas en las etiquetas