Método de encadenamiento en Java
methods chaining (6)
Aunque podemos adivinar la verdadera razón, uno de ellos podría ser estrictamente hablando que no es muy OO.
Si ve métodos como acciones que representan una acción del mundo modelado, el encadenamiento de métodos realmente no encaja en esa imagen.
Otra razón podría ser el caos que puede sobrevenir cuando intentas anular un método encadenado. Imagina esta situación:
class Foo {
Foo chainedMethod() {...}
}
class Bar extends Foo {
Foo chainedMethod() {...} //had to return Foo for Java versions < 1.5
void doStuff();
}
Por lo tanto, cuando intente hacer una new Bar().chainedMethod().doStuff()
, no se compilará. Y ((Bar)new Bar().chainedMethod()).doStuff()
no se ve muy bien, ¿verdad? :)
Mientras respondía algunas preguntas aquí antes y de algún trabajo que he estado haciendo últimamente, me he estado preguntando por qué Java no admite el encadenamiento de métodos en sus clases integradas.
Si tuviera que crear una clase de Car
, por ejemplo, podría hacerlo encadenable reabriendo this
lugar de vacío de la siguiente manera:
public class Car {
private String make;
public Car setMake(String make) {
this.make = make;
return this;
}
}
¿Hay alguna razón particular por la cual las bibliotecas integradas no tienden a hacer las cosas de esta manera? ¿Hay algún inconveniente en el encadenamiento de métodos?
Pude haber pasado por alto algo que explicaría la falta de encadenamiento de métodos; sin embargo, cualquier método setter que devuelva vacío por defecto debería devolver una referencia a esto (al menos en mi opinión debería). Esto haría que situaciones como la siguiente sean mucho más limpias.
container.add((new JLabel("label text")).setMaximumSize(new Dimension(100,200)));
en lugar de la más larga aliento: Nota: no le impediría codificar de esta manera si lo desea.
JLabel label = new JLabel("label text");
label.setMaximumSize(new Dimension(100,200));
container.add(label);
Me interesaría mucho escuchar las razones detrás de esta decisión, si tuviera que adivinar que habría una sobrecarga asociada con esto y, por lo tanto, solo debería usarse cuando sea necesario.
Eh. Hay argumentos de legibilidad para hacer en ambas direcciones; hay algo así como tratar de poner demasiado en una sola línea.
Pero, sinceramente, sospecho que aquí es por razones históricas: el comportamiento dominante de "encadenamiento" no se había popularizado o conocido cuando, por ejemplo, se estaba desarrollando Swing. Se podría argumentar que debería haber sido agregado más adelante, pero cosas así tienden a crear incompatibilidades binarias y otros problemas que Sun / Oracle históricamente han sido extremadamente cautelosos.
Las bibliotecas más recientes de JDK, por ejemplo, ByteBuffer
para un ejemplo importante y bien conocido, han proporcionado un comportamiento de encadenamiento y similares, donde tiene sentido.
El encadenamiento de métodos se utiliza generalmente con el patrón de generador y puede verlo en la clase StringBuilder
. Aparte de eso, el encadenamiento de métodos puede hacer que la separación entre comandos y creaciones sea menos clara, por ejemplo, ¿debería el repaint()
ser parte de la interfaz fluida? Entonces podría tener:
container.add(label).repaint().setMaximumSize(new Dimension(100,200)));
y de repente el orden de mis llamadas se vuelve importante y puede ocultarse en el método de encadenamiento.
El motivo para no implementar el encadenamiento de métodos sería alguno de los siguientes:
El mayor problema para Method Chaining es el problema final. Si bien hay soluciones alternativas, por lo general, si se encuentra con esto, es mejor utilizar una función anidada. Las funciones anidadas también son una mejor opción si te metes en un lío con las variables de contexto.
No hay garantía de que un objeto fuera de la cadena realmente devuelva un objeto válido, no nulo. Además, la depuración de este estilo de código a menudo es mucho más difícil ya que muchos * IDE * s no evaluarán la llamada al método en el momento de la depuración como un objeto que puede inspeccionar
Puede ser confuso cuando llama rutinas a otras clases para pasar argumentos a uno de los métodos de encadenamiento, cuando hay muchos parámetros que aprobar, principalmente porque las líneas son muy largas.
También hay un problema de rendimiento, que trabajará duro en la memoria
Otra razón por la que puedo pensar es en el rendimiento , o más precisamente: no pagues por algo que no usas. return this
después de que todos y cada uno de los métodos no sean muy costosos, pero aún así se requieren unos pocos ciclos de CPU adicionales y un registro de la CPU.
Incluso hubo una idea de agregar un return this
implícito a cada método que declarara un void
retorno void
, pero fue rechazado.
Realmente estás preguntando sobre la Ley de Demeter
"Solo habla con tus amigos más cercanos"
Tenga en cuenta que el enlace anterior es un recurso maravilloso, pero puede pasar mucho tiempo allí y no obtener la respuesta que estaba buscando. :-)