Object Calistenics – Aplica la Ley de Demeter
En esta entrada os voy a hablar de la Ley de Demeter. Siempre os he comentado sobre la responsabilidad que cada objeto ha de tener sobre si misma, y esto realmente con práctica llega a ser fácil identificarlo.
Una vez mas aplicando la Ley de Demeter provocamos que la responsabilidad de los objetos recáiga sobre ellos mismos, sin cedersela a nadie mas, ya que es importante tener encapsulada nuestra información, y esto evitará el acoplamiento entre objectos.
Es importante saber que esta ley se basa en que una clase no debe conocer los entresijos de los objetos que maneja. Si una clase o entidad contiene lógica de negocio, o sea, si no estamos hablando de una clase anémica, este debe ocultar su estructura, esto se conoce como “Principio de menor conocimiento“.
La ley de Demeter evita lo que se denomina el “Choque de trenes“, ya que el código que se utiliza se parece bastante a un tren y sus vagones.
Volvamos al ejemplo de Robot, ahora pensemos que Position ya no es una propiedad de Robot tipo int, si no que es una clase Position() y que esta tiene dos propiedades para saber donde está el Robot localizado, x e y, y que Position tiene un método llamado Posicionar() donde maneja a x e y
public class Robot
{
public string Name { get; set; }
public Poderes Poderes { get; set; }
public Position Position;
public Robot()
{
Poderes = new Poderes();
Position = new Position(0,0);
}
}
public class Position
{
public int X { get; set; }
public int Y { get; set; }
public Position(int x, int y)
{
X = x;
Y = y;
}
public void Posicionar(int x, int y)
{
X = x;
Y = y;
}
}
var robot = new Robot();
robot.Position.Posicionar(10,9);
Lenguaje del código: JavaScript (javascript)
Podemos ver como para mover al Robot hemos de hacerlo así ==> robot.Position.Posicionar(10,9), y esto no es correcto, y podríamos decir que tenemos en nuestro código un Feature Envy, o sea, que una clase sabe demasiado sobre otra, tiene envidia de ella. Desde una instancia nueva creada de Robot, no se debería poder acceder directamente al método Posicionar() a través de Position.
Para solventar este problema, lo podríamos resumir en “Habla sólo con tus amigos, no con extraños“, o “Tell, don’t ask” o sea tratar de que un objeto solo se relacione consigo mismo en la medida de lo posible, que recaiga sobre él la responsabilidad que tiene que tener asociada con sus propiedades. Hemos de encapsular lo máximo posible sus propiedades y acciones en su propia clase y no ceder estas a ninguna otra, y digo lo máximo posible ya que no en todos los casos podemos ceñirnos a esta regla al 100%, al fin y al cabo no deja de ser una regla.
Vamos a refactorizar el código para ver como sería mas correcto acceder a esta propiedad y aplicar lo máximo posible la Ley de Demeter
public class Robot
{
public string Name { get; set; }
private Poderes Poderes;
private Position Position;
public Robot()
{
Poderes = new Poderes();
Position = new Position(0,0);
}
public void Mover(int x, int y)
{
this.Position.Posicionar(x,y);
}
}
public class Position
{
private int X { get; set; }
private int Y { get; set; }
public Position(int x, int y)
{
X = x;
Y = y;
}
public void Posicionar(int x, int y)
{
X = x;
Y = y;
}
}
var robot = new Robot();
robot.Mover(10,9);
Lenguaje del código: JavaScript (javascript)
Ahora ya inicializamos una nueva instancia de Robot y llamámos al método Mover(), por lo que no estamos accediendo ni a propiedades ni a métodos propios de Position(), y no tendríamos el Feature Envy del que hablábamos arriba, además ya tenemos un nombre de método mas identificativo, unido a la instancia de Robot, usando robot.Mover(10,9), cualquier persona que lo lea sabría identificar exactamente que acción se está realizando sobre Robot.
Se que esta no es la mejor forma de refactorizar ni la mejor forma de hacerlo, pero al menos espero que os haya sabido transmitir la idea, y a quien no conociera esta regla, le haya servido como una introducción para que pueda ir profundizando mas en esta técnica.