¿Qué es la Ley de Deméter?

Empecemos con Wikipedia:

Más formalmente, la Ley de Demeter para funciones requiere que un método m de un objeto O solo pueda invocar los métodos de los siguientes tipos de objetos:

  1. O en sí
  2. parámetros de m
  3. Cualquier objeto creado / instanciado dentro de m
  4. Objetos componentes directos de O
  5. Una variable global, accesible por O, en el ámbito de m

Regla 1:

public class ClassOne { public void method1() { method2(); } public void method2() { } } 

Regla 2:

 public class ClassOne { public void method1(ClassTwo classTwo) { classTwo.method2(); } } class ClassTwo { public void method2() { } } 

Regla 3:

 public class ClassOne { public void method1() { ClassTwo classTwo = new ClassTwo(); classTwo.method2(); } } class ClassTwo { public void method2() { } } 

Regla 4 (gracias @juharr):

 public class ClassOne { private ClassTwo classTwo; public void method1() { classTwo = new ClassTwo(); classTwo.method2(); } } class ClassTwo { public void method2() { } } 

Regla 5:

 ? 

¿Puede alguien ayudarme con la Regla 5?


¿Y no implica la Ley de Deméter que el encadenamiento es malo?

 User.getName().getLastName(); 

Esto conduce a un alto acoplamiento.


¿No es “Dile, no preguntes” un principio similar?

Entonces, ¿esto es todo? ¿Estoy equivocado acerca de algo? ¿Cómo puedes obedecer la Ley de Deméter?

“Dile que no preguntes” es un poco diferente.

Demeter: no consiga algo para obtener algo de eso para hacer algo en la cosa final.

TDA: no recupere “información” de otro objeto para luego tomar una decisión al respecto. Ejemplo simple:

 if (someList.size() == 0) { bla 

contra

 if (someList.isEmpty()) { bla 

En ambos casos, estás llamando a un método en algún otro objeto; pero hay una diferencia clave: la primera llamada expone el estado “interno” de ese otro objeto; en el que luego tomar una decisión. Considerando que, en el “TDA” mejoró la segunda versión; dejas esa “evaluación de estado” dentro de ese otro objeto; por lo tanto de alguna manera reducir el acoplamiento.

El quinto es difícil de representar en C # o Java, ya que técnicamente no admiten variables globales. Sin embargo, en un patrón de diseño que es similar en principio, podría tener, por ejemplo, una clase de configuración que solo contenga valores de configuración estáticos accesibles globalmente, como (C #):

 internal class MyConfiguration { private static String MyConfigurationValue; // set in constructor MyConfiguration(){ MyConfigurationValue = DoSomethingToLoadValue(); } public static String GetMyConfigurationValue(){ return MyConfigurationValue; } } 

En este caso (suponiendo que el patrón de diseño fuera aceptable en todas las demás formas), la Ley de Demeter lo permitiría, ya que es accesible a nivel mundial y pretende ser así.

Un ejemplo para la Regla 5 sería:

 public class ClassOne { public void method1() { classTwo.STATIC_INSTANCE.method2(); } } class ClassTwo { public static final ClassTwo STATIC_INSTANCE = ...; public void method2() { } } 

Las enumeraciones funcionan básicamente de esta manera, y está bien acceder a las enumeraciones.


Tu ejemplo

 user.getName().getLastName(); 

obviamente contradice las leyes, ya que el objeto que obtiene de “getName ()” no se incluirá en ninguna de las categorías enumeradas. Nota: esto es incorrecto incluso si no está usando llamadas en cadena:

 Name name = user.getName(); name.getLastName(); // <- this is still wrong 

ya que el objeto "nombre" todavía no cae en ninguna de las categorías enumeradas.

Sin embargo, cosas como esta están bien:

 reportBuilder.withMargin(5).withFooter(10) .withBorder(Color.black).build(); 

¿Por qué se permite esto? Porque o bien recuperas el mismo objeto (el reportBuilder) cada vez, o tal vez un nuevo objeto cada vez si el constructor se implementa como inmutable. De cualquier manera, cae en la ley 2 o 3, así que está bien de cualquier manera.


Tu tercera pregunta es "cómo obedecer". Bueno, esta es una pregunta compleja, pero solo para comenzar, ¡piense qué tipo de métodos están realmente prohibidos por las leyes!

Simplemente ponga las leyes en negativo: no deberíamos llamar a métodos en objetos que ya están allí (porque los nuevos objetos están exentos) y no son mi objeto, ni los campos de mi objeto, ni mis parámetros. ¡Así que deja objetos que están en los campos de otros objetos!

Básicamente, eso significa que no debería poder "obtener" acceso a objetos que no son usted, ni en sus campos, ni parámetros directos. Que resumiría como "no getters"!