¿Es una mala práctica hacer que un colocador devuelva "esto"?

Resuelto Ken Liu asked hace 15 años • 27 respuestas

¿Es una buena o mala idea hacer que los configuradores en Java devuelvan "esto"?

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

Este patrón puede ser útil porque entonces puedes encadenar configuradores como este:

list.add(new Employee().setName("Jack Sparrow").setId(1).setFoo("bacon!"));

en lugar de esto:

Employee e = new Employee();
e.setName("Jack Sparrow");
...and so on...
list.add(e);

...pero en cierto modo va en contra de la convención estándar. Supongo que podría valer la pena simplemente porque puede hacer que ese colocador haga algo más útil. He visto que este patrón se usa en algunos lugares (por ejemplo, JMock, JPA), pero parece poco común y generalmente solo se usa para API muy bien definidas donde este patrón se usa en todas partes.

Actualizar:

Lo que he descrito es obviamente válido, pero lo que realmente estoy buscando son algunas ideas sobre si esto es generalmente aceptable y si existen dificultades o mejores prácticas relacionadas. Conozco el patrón Builder, pero es un poco más complicado que lo que estoy describiendo: como lo describe Josh Bloch, hay una clase Builder estática asociada para la creación de objetos.

Ken Liu avatar Aug 28 '09 11:08 Ken Liu
Aceptado

No es una mala práctica. Es una práctica cada vez más común. La mayoría de los lenguajes no requieren que usted trate con el objeto devuelto si no lo desea, por lo que no cambia la sintaxis de uso del configurador "normal", pero le permite encadenar configuradores.

Esto comúnmente se denomina patrón constructor o interfaz fluida .

También es común en la API de Java:

String s = new StringBuilder().append("testing ").append(1)
  .append(" 2 ").append(3).toString();
cletus avatar Aug 28 '2009 04:08 cletus

Para resumir:

  • se llama "interfaz fluida" o "encadenamiento de métodos".
  • Esto no es Java "estándar", aunque cada vez se ve más en estos días (funciona muy bien en jQuery)
  • viola la especificación JavaBean, por lo que romperá con varias herramientas y bibliotecas, especialmente con los constructores JSP y Spring.
  • puede impedir algunas optimizaciones que la JVM normalmente haría
  • Algunas personas piensan que limpia el código, otras piensan que es "espantoso".

Un par de puntos más no mencionados:

  • Esto viola el principio de que cada función debe hacer una (y sólo una) cosa. Puede que creas o no en esto, pero en Java creo que funciona bien.

  • Los IDE no los generarán por usted (de forma predeterminada).

  • Finalmente, aquí hay un punto de datos del mundo real. He tenido problemas al usar una biblioteca construida como esta. El generador de consultas de Hibernate es un ejemplo de esto en una biblioteca existente. Dado que los métodos set* de Query devuelven consultas, es imposible saber con solo mirar la firma cómo usarlo. Por ejemplo:

    Query setWhatever(String what);
    
  • Introduce una ambigüedad: ¿el método modifica el objeto actual (su patrón) o, tal vez Query sea realmente inmutable (un patrón muy popular y valioso), y el método devuelve uno nuevo? Simplemente hace que la biblioteca sea más difícil de usar y muchos programadores no aprovechan esta característica. Si los setters fueran setters, sería más claro cómo usarlo.

ndp avatar Sep 02 '2009 03:09 ndp