Object Calisthenics – Evitar más de dos atributos de instancia.
Bueno, pues una vez más, vamos a ver una regla de Object Calisthenics, que veremos que vuelve a está relacionada directamente con la responsabilidad única, es la de “Evitar más de dos atributos de instancia“.
Esta regla nos viene a decir que las clases deben ser responsables del manejo de una única variable de instancia, aunque algunas requerirán de dos, y con esto reduciremos la cohesión de dicha clase. Muchas veces comenzamos a declarar una clase introduciendo una gran cantidad de variables sin pararnos a pensar de que forma podemos disociar estas, y sin tratar de separar responsabilidades, y con esto lo que estamos haciendo es mezclar responsabilidad, y haciendo que una clase haga mas cosas de las que realmente debería hacer.
Como ya he comentado en muchísimas ocasiones, no debemos tomarnos esto al pie de la letra, ya que siempre no está de nuestro lado tomar esta decisión de una forma directa, como por ejemplo en entidades que ya nos vienen supeditadas por como esté estructurada la base de datos, y ahí si se nos puede dar un claro caso de manejar una gran cantidad de variables, y aunque aquí también podríamos separar responsabilidades no es el caso en el que nos estamos centrando.
Aunque mi opinión es que si debemos ceñirnos en la mayoría de lo posible a esta caso y tratar de separar las responsabilidades de la clase, ya que de este modo se nos quedará una clase mas clara, entendible y por norma general con no mas de 50 líneas, como se ha visto en la entrada anterior.
Veamos un ejemplo volviendo a los Robots:
Tal y como hablábamos en la entrada anterior con el ejemplo de la recolección de Basura por parte de los Robots, seguimos teniendo la clase Robot, pero ahora hemos dicho que recolectan Basura que depositan en un Centro de reciclado.
Se nos podría quedar una clase de este estilo de primeras sin pensar en separar responsabilidades:
public class Robot
{
public string Name { get; set; }
public Position Position { get; set; }
public List<string> Basura { get; set; }
public string NombreCentroReciclado { get; set; }
public string DireccionCentroReciclado { get; set; }
public Robot()
{
Position = new Position(0, 0);
}
}
var robot = new Robot
{
Name = "Pepito Grillo",
Basura = new List<string> { "bote refresco", "bolsa pipas", "botella agua" },
DireccionCentroReciclado = "Poligono Industrial Recycling",
NombreCentroReciclado = "Reciclando S.A."
};
Lenguaje del código: JavaScript (javascript)
En este ejemplo vemos como Robot() tiene por un lado una variable Name, para el nombre del Robot, también Basura, que es una lista con toda la basura que ha recogido, la DireccionCentroReciclado, y el NombreCentroReciclado, para este caso a Robot le estamos dando la responsabilidad, no solo de conocer donde está el centro de reciclado y su Nombre, si no de asignar esa dirección y ese nombre del centro, y Robot() no debería encargarse de realizar ese tipo de asignación.
Si en un futuro quisiéramos validar que la dirección del centro de reciclado o si su nombre es correcto, debería hacerlo Robot(), ya que está en su clase, y el tampoco ha de validar esto, y esta es la forma en la que una clase se nos podría hacer muy larga, o haría muchas mas cosas de las que debe y no sería ni clara, ni legible ni fácilmente entendible.
Para evitar este problema hemos de refactorizar la clase, vamos a hacerlo y a explicar el por qué hacerlo así:
public class Robot
{
public string Name { get; set; }
public Position Position { get; set; }
public CentroReciclado CentroReciclado { get; set; }
public Robot()
{
Position = new Position(0, 0);
}
public void DepositarBasura(string basura)
{
CentroReciclado.RecibirBasura(basura);
}
}
var centroReciclado = new CentroReciclado()
{
Nombre = "Reciclando S.A.",
Direccion = "Poligono Industrial Recycling",
};
var robot = new Robot
{
Name = "Pepito Grillo",
CentroReciclado = centroReciclado,
};
robot.DepositarBasura("botella agua");
Lenguaje del código: JavaScript (javascript)
Con esta refactorización podemos ver que hemos sacado de la ecuación de Robot a Basura, y hemos convertido las variables de NombreCentroReciclado y DireccionCentroReciclado en la clase CentroReciclado, por lo que esta nueva clase se nos ha quedado de esta forma:
public class CentroReciclado
{
public string Nombre { get; set; }
public string Direccion { get; set; }
private Basuras Basuras { get; set; }
public CentroReciclado()
{
Basuras = new Basuras();
}
public void RecibirBasura(string basura)
{
Basuras.Add(basura);
}
public void Recicla()
{
if (Basuras.values.Count > 10)
{
Basuras.EstadoBasuras = EstadoBasuras.Reciclada;
}
}
}
public class Basuras
{
public List<string> values { get; set; }
public EstadoBasuras EstadoBasuras { get; set; }
public Basuras()
{
values = new List<string>();
}
public void Add(string value)
{
values.Add(value);
}
}
public enum EstadoBasuras
{
Default = 0,
SinReciclar = 1,
Reciclada = 2,
}
Lenguaje del código: JavaScript (javascript)
Con esto hemos conseguido refactorizar la clase Robot(), para que tenga, en este caso menos variables de Instancia en la clase de las que antes tenía, hemos reducido la cohesión de la clase. Se ha pasado responsabilidad a quien realmente la tiene y las validaciones como la que vemos en el método Recicla() han pasado a ser responsabilidad de la clase CentroReciclado().
Personalmente a mi me parece una de las reglas mas difícil de explicar y sobre todo de cumplir, y creo que lo mas importante aquí no es el tener dos variables de instancia, o tres o cuatro, para mi lo mas importante es saber delegar la responsabilidad a la clase propia.
En un plano idílico si tendríamos solo dos variables de instancia por clase, pero esto en la mayoría de casos cumplirlo es muy complejo, por ese motivo he querido seguir aplicando el ejemplo de Robot(), hubiera sido mas fácil aplicar esta regla con el típico ejemplo de Nombre y Apellidos, pero quería tratar de plasmar con una clase un poco mas compleja, lo realmente complicada que puede hacerse esta regla cuando una clase está mas ligada a un Negocio, y sobre todo si en un momento dado este está muy acoplado.
Y esto no quiere decir que en este ejemplo no pudiéramos cumplir la regla, habría que refactorizar bastante el código, pero podríamos perfectamente adaptarnos a cumplirla.
¿ Hasta que punto pensáis que esta regla hemos de cumplirla al pie de la letra ? Os leo en comentarios!!
donde esta class BASURAS?
Buenos días LEV, en primer lugar, gracias por leer mi blog, espero te sirva de ayuda. La clase Basuras() la he obviado, pero si te parece importante la expongo para que se vea mejor el flujo.
Un saludo!