¿Es una buena o mala idea hacer que los setters en Java devuelvan "esto"?
public Employee setName(String name){
this.name = name;
return this;
}
Este patrón puede ser útil porque puedes encadenar a los setters de esta manera:
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 va en contra de la convención estándar. Supongo que podría valer la pena solo porque puede hacer que ese setter haga algo más útil. He visto que este patrón usa algunos lugares (por ejemplo, JMock, JPA), pero parece poco común, y solo se usa generalmente 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 es algunas reflexiones sobre si esto es generalmente aceptable y si existen dificultades o prácticas recomendadas relacionadas. Sé sobre el patrón Builder, pero está un poco más involucrado que lo que estoy describiendo, como lo describe Josh Bloch, hay una clase Builder estática asociada para la creación de objetos.
fuente
this
. A veces, incluso modifico la función para que, en lugar de devolver un valor, funcione en un miembro del objeto, solo para poder hacer esto. Es maravilloso. :)Respuestas:
No creo que haya nada específicamente malo en ello, es solo una cuestión de estilo. Es útil cuando:
Las alternativas a este método pueden ser:
Si solo va a establecer algunas propiedades a la vez, diría que no vale la pena devolver 'esto'. Ciertamente se cae si luego decide devolver algo más, como un indicador / mensaje de estado / éxito.
fuente
No es una mala práctica. Es una práctica cada vez más común. La mayoría de los idiomas no requieren que trate con el objeto devuelto si no lo desea, por lo que no cambia la sintaxis de uso del setter "normal" pero le permite encadenar los setters juntos.
Esto se llama comúnmente un patrón de construcción o una interfaz fluida .
También es común en la API de Java:
fuente
bla.foo.setBar1(...) ; bla.foo.setBar2(...)
cuando podría escribirbla.foo /* newline indented */.setBar1(...) /* underneath previous setter */ .setBar2(...)
(no puede usar saltos de línea en un comentario SO como este :-( ... espero que obtenga el punto teniendo en cuenta 10 de esos setters o llamadas más complejas)Para resumir:
Un par de otros puntos no mencionados:
Esto viola el principio de que cada función debe hacer una (y solo una) cosa. Puede o no creer en esto, pero en Java creo que funciona bien.
Los IDEs no los van a generar (por defecto).
Finalmente, aquí hay un punto de datos del mundo real. He tenido problemas al usar una biblioteca construida así. 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:
Introduce una ambigüedad: el método modifica el objeto actual (su patrón) o, quizás, la consulta es realmente inmutable (un patrón muy popular y valioso), y el método está devolviendo uno nuevo. Simplemente hace que la biblioteca sea más difícil de usar, y muchos programadores no explotan esta característica. Si los setters fueran setters, sería más claro cómo usarlo.
fuente
this
no es una ciencia compleja de cohetes. :-)Prefiero usar métodos 'con' para esto:
Así:
Advertencia : esta
withX
sintaxis se usa comúnmente para proporcionar "establecedores" para objetos inmutables, por lo que las personas que llaman de estos métodos pueden esperar razonablemente que creen nuevos objetos en lugar de mutar la instancia existente. Tal vez una redacción más razonable sería algo como:Con la convención de nombres chainsetXyz (), prácticamente todos deberían estar contentos.
fuente
get
, aset
y awith
para cada campo de clase. Sin embargo, sigue siendo una solución interesante. :)Project Lombok
las@Getter/@Setter
anotaciones ... eso sería fantástico para encadenar. O podría usar algo muy parecido alKestrel
combinador ( github.com/raganwald/Katy ) que usan los demonios JQuery y Javascript.with
prefijo es una convención diferente. como @qualidafial dio un ejemplo. los métodos con el prefijowith
no deberían regresar,this
sino una nueva instancia como la instancia actual, perowith
ese cambio. Esto se hace cuando desea que sus objetos sean inmutables. Entonces, cuando veo un método con el prefijowith
Asumo que obtendré un nuevo objeto, no el mismo objeto.Si no desea regresar
'this'
del configurador pero no desea usar la segunda opción, puede usar la siguiente sintaxis para establecer las propiedades:Como comentario aparte, creo que es un poco más limpio en C #:
fuente
equals
método. Hay formas muy claras de tratar con clases anónimasequals
si sabes lo que estás haciendo.No solo rompe la convención de getters / setters, también rompe el marco de referencia del método Java 8.
MyClass::setMyValue
es unBiConsumer<MyClass,MyValue>
, ymyInstance::setMyValue
es unConsumer<MyValue>
. Si le devuelve su setterthis
, entonces ya no es una instancia válidaConsumer<MyValue>
, sino unaFunction<MyValue,MyClass>
, y causará que se rompa cualquier cosa que use referencias de métodos a esos setters (suponiendo que sean métodos nulos).fuente
Consumer<A>
yFunction<A,B>
proporcionando una implementación predeterminada devoid accept(A a) { apply(a); }
. Entonces se puede usar fácilmente como uno y no romperá ningún código que requiera una forma específica.No conozco Java, pero lo hice en C ++. Otras personas han dicho que hace que las líneas sean muy largas y difíciles de leer, pero lo he hecho así muchas veces:
Esto es aún mejor:
al menos eso creo. Pero puedes invitarme a votar y llamarme un programador horrible si lo deseas. Y no sé si puedes hacer esto en Java.
fuente
//
después de cada método si configura su IDE para que no se una a las líneas ya ajustadas (por ejemplo, Eclipse> Propiedades> Java> Estilo de código> Formateador> Ajuste de línea> Nunca unir líneas ya ajustadas).Este esquema (juego de palabras), llamado 'interfaz fluida', se está volviendo bastante popular ahora. Es aceptable, pero en realidad no es mi taza de té.
fuente
Como no devuelve nulo, ya no es un configurador de propiedades JavaBean válido. Eso podría importar si eres una de las siete personas en el mundo que usa herramientas visuales "Bean Builder", o una de las 17 que usan elementos JSP-bean-setProperty.
fuente
Al menos en teoría , puede dañar los mecanismos de optimización de la JVM al establecer dependencias falsas entre llamadas.
Se supone que es azúcar sintáctica, pero de hecho puede crear efectos secundarios en la máquina virtual de Java 43 súper inteligente.
Por eso voto no, no lo use.
fuente
set
método depende del primerset
método, aunque lo conoce el programador.-XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining
El java7 jdk definitivamente integra métodos encadenados, y realiza alrededor del mismo número de iteraciones que se necesitan para marcar los establecedores de vacíos como activos y también en línea. Creo que subestimas el poder de los algoritmos de poda de código de operación de JVM; si sabe que está devolviendo esto, omitirá el código de operación jrs (declaración de devolución de Java) y simplemente lo dejará en la pila.No es una mala práctica en absoluto. Pero no es compatible con JavaBeans Spec .
Y hay muchas especificaciones que dependen de esos accesores estándar.
Siempre puedes hacer que coexistan entre sí.
Ahora podemos usarlos juntos.
Aquí viene otra versión para objeto inmutable.
Ahora podemos hacer esto.
fuente
some
campo. En segundo lugar, debe agregar una salvaguardia y el conjuntosome
denull
de acumulación () por lo queSome
es verdaderamente inmutable, de lo contrario se podría llamarbuilder.value()
en la misma instancia del constructor de nuevo. Y, por último, sí, tiene un generador, peroSome
todavía tiene un constructor público, lo que significa que no defiende abiertamente el uso del generador, es decir, el usuario no lo sabe más que probar o buscar un método para establecer un método personalizadovalue
en absoluto.Si utiliza la misma convención en toda la aplicación, parece estar bien.
Por otro lado, si una parte existente de su aplicación usa una convención estándar, me apegaría a ella y agregaría constructores a clases más complicadas
fuente
Paulo Abrantes ofrece otra forma de hacer que los configuradores de JavaBean sean fluidos: defina una clase de generador interno para cada JavaBean. Si está utilizando herramientas que se desconciertan por los setters que devuelven valores, el patrón de Paulo podría ayudar.
fuente
Estoy a favor de que los setters vuelvan "esto". No me importa si no es compatible con los frijoles. Para mí, si está bien tener la expresión / declaración "=", entonces los establecedores que devuelven valores están bien.
fuente
Solía preferir este enfoque, pero he decidido no hacerlo.
Razones:
El patrón Builder que vi no usa la convención setFoo (foo) .setBar (bar) sino más foo (foo) .bar (bar). Quizás por exactamente esas razones.
Es, como siempre, una cuestión de gustos. Simplemente me gusta el enfoque de "menos sorpresas".
fuente
Este patrón particular se llama Método de encadenamiento. Enlace de Wikipedia , esto tiene más explicaciones y ejemplos de cómo se hace en varios lenguajes de programación.
PD: Solo pensé en dejarlo aquí, ya que estaba buscando el nombre específico.
fuente
A primera vista: "¡Horrible!".
Pensándolo mejor
en realidad es menos propenso a errores que
Muy interesante Añadiendo idea a la bolsa de herramientas ...
fuente
list
al principio.Sí, creo que es una buena idea.
Si pudiera agregar algo, ¿qué pasa con este problema?
Esto funcionará:
¡Eclipse no lo aceptará! :
Esto se debe a que setName () devuelve un People y no un Friend, y no hay PeoplesetNickName.
¿Cómo podríamos escribir setters para devolver la clase SELF en lugar del nombre de la clase?
Algo como esto estaría bien (si existiera la palabra clave SELF). ¿Existe esto de todos modos?
fuente
class C<S extends C<S>>
, que es más seguro que un planoS extends C
. a) SiA extends B
, yB extends C<B>
, y tiene una A, solo sabe que un B se devuelve a menos que A anule todos y cada uno de los métodos. b) No puede denotar un local, no crudoC<C<C<C<C<...>>>>>
.En general, es una buena práctica, pero es posible que necesite que las funciones de tipo conjunto usen el tipo booleano para determinar si la operación se completó con éxito o no, esa también es una forma. En general, no hay dogma para decir que esto es bueno o la cama, proviene de la situación, por supuesto.
fuente
De la declaración
estoy viendo dos cosas
1) Declaración sin sentido. 2) Falta de legibilidad.
fuente
Esto puede ser menos legible
o esto
Esto es mucho más legible que:
fuente
He estado haciendo mis setters durante bastante tiempo y el único problema real es con las bibliotecas que se adhieren a los estrictos getPropertyDescriptors para obtener los accesos de bean bean reader / writer. En esos casos, su "bean" de Java no tendrá los escritores que usted esperaría.
Por ejemplo, no lo he probado con seguridad, pero no me sorprendería que Jackson no los reconozca como setters al crear objetos java a partir de json / maps. Espero estar equivocado en este caso (lo probaré pronto).
De hecho, estoy desarrollando un ORM ligero centrado en SQL y tengo que agregar algo de código entre getPropertyDescriptors a los creadores reconocidos que devuelven esto.
fuente
Hace mucho tiempo respondí, pero mis dos centavos ... Está bien. Desearía que esta interfaz fluida se usara con más frecuencia.
La repetición de la variable 'factory' no agrega más información a continuación:
Esto es más limpio, en mi humilde opinión:
Por supuesto, como una de las respuestas ya mencionadas, la API de Java tendría que modificarse para hacer esto correctamente en algunas situaciones, como la herencia y las herramientas.
fuente
Es mejor usar otras construcciones de lenguaje si están disponibles. Por ejemplo, en Kotlin, usaría con , aplicaría o dejaría . Si usa este enfoque, realmente no necesitará devolver una instancia de su configurador.
Este enfoque permite que su código de cliente sea:
Aquí hay unos ejemplos.
fuente
Si estoy escribiendo una API, uso "devolver esto" para establecer valores que solo se establecerán una vez. Si tengo otros valores que el usuario debería poder cambiar, en su lugar uso un setter vacío estándar.
Sin embargo, es realmente una cuestión de preferencia y encadenar a los setters se ve bastante bien, en mi opinión.
fuente
Estoy de acuerdo con todos los carteles que afirman que esto rompe las especificaciones de JavaBeans. Hay razones para preservar eso, pero también siento que el uso de este Patrón de Constructor (al que se aludió) tiene su lugar; siempre que no se use en todas partes, debería ser aceptable. "Es lugar", para mí, es donde el punto final es una llamada a un método "build ()".
Por supuesto, hay otras formas de establecer todas estas cosas, pero la ventaja aquí es que evita 1) constructores públicos de muchos parámetros y 2) objetos parcialmente especificados. Aquí, el constructor recopila lo que se necesita y luego llama a su "build ()" al final, lo que puede garantizar que no se construya un objeto parcialmente especificado, ya que esa operación puede tener una visibilidad inferior a la pública. La alternativa sería "objetos de parámetros", pero esa IMHO simplemente empuja el problema un nivel atrás.
No me gustan los constructores de muchos parámetros porque hacen que sea más probable que se pasen muchos argumentos del mismo tipo, lo que puede facilitar la transmisión de argumentos incorrectos a los parámetros. No me gusta usar muchos setters porque el objeto podría usarse antes de que esté completamente configurado. Además, la noción de tener valores predeterminados basados en elecciones anteriores se sirve mejor con un método "build ()".
En resumen, creo que es una buena práctica, si se usa correctamente.
fuente
Mal hábito: un setter establece un getter get
¿Qué hay de declarar explícitamente un método, que lo hace para U
fuente