SOLID - Principios de la programación orientada a objetos


Estos principios, recopilados por Robert C. Martin, conforman una guía de a lo que debería aspirar una aplicación desarrollada con programación orientada a objetos, ya que nos permite generar aplicaciones escalables, abiertas a las modificaciones y, en teoría, más sencillas de probar. En esta entrada repasaremos un poco cuales son y como implementarlos con ejemplos sencillos.

Los principios SOLID son los siguientes:
  • Single responsibility principle
  • Open/Closed
  • Liskov substitution
  • Interface segregation
  • Dependency inversion

Entremos al detalle de cada uno de ellos.

Principio de responsabilidad única (Single responsibility principle)
Una clase, método o proceso tiene su razón de ser y no debería cambiar con el paso del tiempo. De no hacerlo aumentaría su nivel de acoplamiento y sería frágil ante los cambios.

Ejemplo de como NO debe hacerse:
 public class Car : IMachineInfo  
   {  
     double carPrice = 1200; // Este valor puede cambiar  
     public int GetNumOfWheels()  
     {  
       return 4;  
     }  
     public int GetNumOfDoors()  
     {  
       return 4;  
     }  
     public double GetMarketPrice()  
     {  
       return carPrice;  
     }  
     public double GetPriceForRetail() // El cálculo del precio puede variar  
     {  
       return ((GetMarketPrice() * .2) + 1) + GetMarketPrice();  
     }  
   }  

Ejemplo de cómo corregirlo:
   public class MachinePriceCalculator : IPriceHandler // El cálculo lo hace otra clase
   {  
     public double GetPriceForRetail(IMachineInfo machineInfo)  
     {  
       return ((machineInfo.GetMarketPrice() * .2) + 1) + machineInfo.GetMarketPrice();  
     }  
   }  
   public interface IMachineInfo  
   {  
     double GetMarketPrice();  
   }  
   public interface IPriceHandler  
   {  
     double GetPriceForRetail(IMachineInfo machineInfo);  
   }  


Abierto-Cerrado (Open/Closed)
Una entidad de software debe estar abierta a su extensión, no a su modificación. Mediante este principio lograremos que los procesos desarrollados sean menos propensos a errores ante los cambios en los requerimientos. Esto se suele conseguir mediante herencia.

Ejemplo de como NO debe hacerse:
 public class Car  
   {  
     public int NumOfWheels { get; set; }  
     public int NumOfDoors { get; set; }  
     public string Owner { get; set; }  
   }  
   // Esta clase rompe con el principio abierto a extensión, cerrado a modificación  
   // Si se requieren más modificaciones, incumplirá el requisito, ya que no solo  
   // actualiza información, sino que aplica validaciones  
   public class DataAccessClass  
   {  
     public void Update()  
     {  
       Car coche = new Car();  
       if (coche.Owner == "Un valor X")  
       {  
         coche.NumOfDoors = 3;  
       }  
     }  
   }  

Ejemplo de cómo corregirlo:
  public class Car  
   {  
     public int NumOfWheels { get; set; }  
     public int NumOfDoors { get; set; }  
     public string Owner { get; set; }  
   }  
   public class DataAccessClass  
   {  
     public void Update()  
     {  
       Car coche = new Car();  
       ValidateCar(coche);  
     }  
     public void ValidateCar(Car coche)  
     {  
       CarOwner vehiculoValidar = new CarOwner();  
       vehiculoValidar.Validate(coche);  
     }  
   }  
   public abstract class Validaciones  
   {  
     public abstract void Validate(Car coche);  
   }  
   public class CarOwner : Validaciones  
   {  
     public override void Validate(Car coche)  
     {  
       if (coche.Owner == "Un valor X")  
       {  
         coche.NumOfDoors = 3;  
       }  
     }  
   }  


Sustitución de Liskov (Liskov substitution)
Mediante este principio podremos validar que nuestras abstracciones son correctas, ya que se basa en que una clase que hereda de otra puede usarse como su padre sin que eso afecte al funcionamiento de este. Con el siguiente ejemplo lo veremos claro.

[EJEMPLO EN CONSTRUCCIÓN]

Principio de segregación de interfaces (Interface segregation)
Este principio dicta que no deberían implementarse interfaces que no vayan a emplearse en su conjunto, ya que si posee partes que no son necesarias, esa interfaz seguramente esté obligando a generar código innecesario.

[EJEMPLO EN CONSTRUCCIÓN]

Inversión de dependencias (Dependency inversion)
Se debe depender de abstracciones y no de implementaciones de código concretas, lo que quiere decir que diversas clases o métodos pueden depende de una abstracción pero esta es independiente de los detalles.

[EJEMPLO EN CONSTRUCCIÓN]

No hay comentarios:

Publicar un comentario