simbolo significado persefone olimpo mito hestia dioses demeter caracteristicas java oop solid-principles

java - significado - ¿Cómo obedecer la Ley de Deméter?



hestia (4)

¿Tendría una banda que responda a la pregunta de quién toca este instrumento?

public String whoIsPlaying(String instrument);

Entonces, si necesitas el nombre de un guitarrista, dirías:

band.whoIsPlaying("guitar");

Nada te impide hacer ping a otros instrumentos también.

Cada vez que veo artículos sobre la Ley de Deméter, el autor nunca parece dar un ejemplo sólido de cómo obedecer esta ley. Todos explican qué es y muestran un ejemplo de violar la ley, pero eso es fácil.

Probablemente hay muchas formas de obedecer esta ley (el buen diseño y la planificación son uno), pero en términos muy simples, ¿sería esta una manera de obedecerla?

Digamos que tengo una clase con estas propiedades:

public class Band { private Singer singer; private Drummer drummer; private Guitarist guitarist; }

Estoy en algún lugar del programa y tengo una instancia de esta clase de Band y quiero el nombre de los guitarristas, lo que generalmente veo es algo como:

guitaristName = band.getGuitarist().getName();

Ese no parece tan malo, ya que no está entrando demasiado en la cadena, pero la Ley de Deméter dice que tal vez debería hacerse de esta manera:

guitaristName = band.getGuitaristName();

y mi clase de Band tiene un método:

public String getGuitaristName() { return guitarist.getName(); }

¿Es así como se supone que debes obedecer la ley?

Gracias.


Creo que la idea de la ley es, como dice Dancrumb más arriba, garantizar que las personas accedan a los objetos en el nivel adecuado.

Imagina que nuestra clase de Band modela la recepción de las oficinas de la banda. Su trabajo es actuar como asistente de los miembros de la banda y tratar con cualquiera que quiera interactuar con la banda.

Ahora, digamos que tuvimos un promotor de giras de una compañía de relaciones públicas que quiere armar algunos materiales de relaciones públicas para su próxima gira. Podríamos modelarlo con una clase:

class TourPromoter { public String makePosterText(Band band) { String guitaristsName = band.getGuitarist().getName(); String drummersName = band.getDrummer().getName(); String singersName = band.getSinger().getName(); StringBuilder posterText = new StringBuilder(); posterText.append(band.getName() posterText.append(" featuring: "); posterText.append(guitaristsName); posterText.append(", "); posterText.append(singersName); posterText.append(", ") posterText.append(drummersName); posterText.append(", ") posterText.append("Tickets £50."); return posterText.toString(); } }

En la vida real, esto es equivalente al promotor de la gira que llama a la oficina y dice:

  • Tour Promotor: ¿Puedo hablar con tu guitarrista?

  • Recepcionista: OK, lo conseguiré para ti.

  • Guitarrista: Hola, este es el guitarrista.

  • Tour Promter: Hola, estoy armando tu último póster. ¿Sólo quería comprobar tu nombre?

  • Guitarrista: Es Jimmy Page

  • Promotor del Tour: Genial, gracias. Oh, ¿podrías conseguirme tu baterista? ...

Basta con decir que la Autoridad Palestina sería despedida con bastante rapidez. La mayoría de las personas razonables preguntaban "¿No podría haber manejado esa llamada telefónica para nosotros?"

Podríamos tener un método getGuitaristsName() , que técnicamente estaría cumpliendo con la Ley de Demeter, pero aún estamos pidiendo a nuestra clase TourPromoter que recuerde detalles sobre la banda, es decir, que tienen un guitarrista, mientras que esta información realmente debería pertenecer al banda en sí.

Para asegurarnos de que estamos introduciendo métodos de una manera sensata, debemos observar qué es lo que realmente está buscando el promotor de la gira, es decir, los nombres de todos los miembros de la banda. Si modelamos ese método en código, nos da una mayor flexibilidad para realizar cambios en la Band más adelante, sin tener que tocar siquiera TourPromoter :

public class Band { private Singer singer; private Drummer drummer; private Guitarist guitarist; public String[] getMembers() { return {singer.getName(), drummer.getName(), guitarist.getName()}; } } public class TourPromoter { public String makePosterText(Band band) { StringBuilder posterText = new StringBuilder(); posterText.append(band.getName()); posterText.append(" featuring: "); for(String member: band.getMembers()) { posterText.append(member); posterText.append(", "); } posterText.append("Tickets: £50"); return posterText.toString(); } }

Si ahora agregamos un bajista o KeyboardPlayer, solo la clase Banda necesita saber la diferencia y el Promotor del Tour no necesita cambiar. Esto significa que ahora también estamos cumpliendo con el Principio de Responsabilidad Única , es decir, nuestro método makePosterText() solo necesita cambiar si cambiamos nuestro formato de póster, no si la banda cambia.

No creo que la Ley de Demeter te diga qué método necesitas sacar para cumplir con el principio de la mejor manera (por ejemplo, getMembers() lugar de getGuitaristsName() arriba) y de esa manera, creo que eres correcto: le muestra cuándo se rompen las cosas, pero no necesariamente cómo solucionarlos. Sin embargo, tener el LoD en mente significa que debes estar atento a las violaciones que luego pueden solucionarse a través de una combinación de otros principios de diseño, como SRP.


La Ley de Deméter en sí no presenta una metodología para la buena demanda. En el mejor de los casos, es una heurística útil para identificar áreas de código potencialmente problemáticas. Las desviaciones de la ley pueden considerarse un " olor a código "

Puede tener la tendencia de ampliar las interfaces de sus clases, ya que da como resultado métodos de proxy o envoltura para darle acceso a las propiedades que son propiedad de objetos internos. Como resultado, sus ventajas deben compararse con sus desventajas (de crear potencialmente clases y módulos difíciles de manejar).

Se aplica mejor como una herramienta para identificar el código que puede necesitar refactorización. Sin embargo, un simple intercambio de métodos de

a.x.getFoo()

a

a.getXFoo()

está siguiendo la letra de la ley, sin seguir el espíritu (agradecimientos a @TedHopp para ese punto). En su lugar, deberías estar investigando qué intentan hacer los usuarios cuando perforan la abstracción de un objeto para obtener el valor de x y definir ese método en consecuencia. Puede que no sea una tarea trivial, pero es por eso que nos pagan mucho dinero :)


No está aplicando LoD en el nivel apropiado: tanto el Band como el Guitarist deben considerarse parte del mismo módulo y el dilema que tenga se decidirá por razones de máxima conveniencia.

Su pregunta es un ejemplo de un problema mucho más amplio, que me he reunido con frecuencia en libros sobre patrones de diseño y similares: intentan explicar principios de gran alcance, que se refieren al diseño de un sistema complejo, en problemas de tamaño ridículamente reducido. El resultado es simplemente la confusión del lector.

Donde realmente vería este principio en efecto es algo como esto: está utilizando AsyncHttpClient , que es una abstracción construida sobre Netty , que es una abstracción construida sobre Java NIO. Ahora, si la API de AsyncHttpClient te obligó en algún lugar a administrar directamente un objeto NIO de Java, cuya API es mucho más AsyncHttpClient y trata conceptos completamente ajenos a AsyncHttpClient , ese sería un ejemplo de ruptura de LoD.