Principios SOLID

Principios SOLID

¡Hola a todos! En este artículo, hablaré de los principios SOLID, donde detallaré el objetivo de cada principio y cómo aplicarlo.

Si te preguntas qué significa SOLID, es el acrónimo formado con la primera letra de cada principio en inglés.

¿Qué son los principios SOLID?

Son un conjunto de principios o reglas que nos ayudan a mantener nuestro código más flexible y fácil de entender. Los principios SOLID son fundamentales para el desarrollo de software orientado a objetos, evitando que tengamos que utilizar malas prácticas en nuestro código.

A continuación, describo cada principio:

Principio de Responsabilidad Única (Single Responsibility Principle)

Una clase debe tener una sola razón para cambiar, es decir, que una clase debe manejar una sola tarea para evitar que la clase cambie constantemente.

El objetivo principal es prevenir el acoplamiento de métodos para una clase y así promover la cohesión. Dividir las responsabilidades en diferentes clases nos ayuda a tener un código más limpio y entendible.

Un ejemplo con PHP

Supongamos que desarrollamos una aplicación para la gestión de tareas. En este punto, tenemos una clase llamada Tareas que representa las funcionalidades que tendrá la aplicación.

Violando el principio

La clase Tareas tiene varias responsabilidades:

  • Guardar en una base de datos.
  • Enviar notificaciones.
  • Generar reportes.

Esto viola el principio, hace que la clase sea más difícil de entender y tiene demasiado acoplamiento de métodos.

Aplicando el principio

Separamos las responsabilidades en diferentes clases.


Principio Abierto/Cerrado (Open/Closed Principle)

Las clases deben estar abiertas a extensión y cerradas a modificación. Eso significa que las clases deben estar diseñadas para agregar una funcionalidad sin cambiar el código existente de la clase.

El objetivo de este principio es que podamos reutilizar código y, a la larga, facilitar el mantenimiento y agilidad del software.

Veamos un ejemplo: Supongamos que trabajamos con figuras geométricas donde calcularemos el área de cada figura. Tenemos una clase llamada Figura donde manejamos las figuras necesarias para el sistema.

Violando el principio


Cuando trabajamos con una estructura condicional como if-else if-else o switch, somos propensos a tener una nueva condición. En este ejemplo, puede surgir una nueva figura como el cuadrado, por lo que debemos  modificar el método calcularArea().

Aplicando el principio

Para evitar estructuras condicionales, asignamos una clase por figura y las extendemos a una clase abstracta para reutilizar su código.


Principio de Sustitución de LISKOV (LISKOV Substitution Principle)

Establece que una subclase puede ser sustituida por su superclase. Este principio tiene como objetivo aplicar una herencia estricta entre las clases, es decir, cuando tenemos una clase hija, ésta debe reutilizar todos los métodos y atributos de su clase padre.

Veamos un ejemplo: Supongamos que asignamos tareas para cada desarrollador de una empresa. Como parte de lo anterior, definimos una clase Tareas como superclase y una subclase Frontend.


Si la clase hija no puede reemplazar un método de la clase padre, violaríamos el principio. En este caso, un desarrollador Frontend no tiene la tarea de testear.

Aplicando el principio

Separamos las tareas en interfaces para que las clases solo implementen lo que necesitan. En este caso, tenemos 3 interfaces y la clase Frontend solo implementa 2 interfaces porque es lo único que necesita.


Recordemos que las interfaces son contratos donde las clases que las implementan están obligadas a reemplazar lo que tiene cada interfaz: si la interfaz tiene 5 funciones, entonces la clase estará obligada a tener esas 5 funciones. Esta es una manera de tener una herencia más estricta.

Principio de Segregación de la Interfaz (Interface Segregation Principle)

Establece que una interfaz debe ser pequeña. Esto lo podemos tomar como la frase “divide y vencerás” que nos da entender que podemos utilizar varias interfaces en lugar de tener solo una.

El objetivo de este principio es que las interfaces no estén sobrecargadas de funciones irrelevantes en todas las clases que van a implementar la interfaz.

Veamos un ejemplo: Asumiremos que tenemos una interfaz con varios métodos para el control de empleados de un sistema, pero los métodos calcularSalario y generarInformePlanilla no hacen referencia al control de empleados como tal, sino a un control de planillas de empleados. Entonces, las clases estarán obligadas a depender de métodos que no van a utilizar.


Aplicando el principio

Como establece el principio, separamos el trabajo en dos interfaces para evitar el acoplamiento de métodos y que las clases no estén obligadas a tener métodos innecesarios.

Principio de Inversión de Dependencia (Dependency Inversion Principle)

Establece que las clases o módulos de alto nivel no deben depender de clases o módulos de bajo nivel, sino de abstracciones.

El objetivo de este principio es desacoplar las clases y manejar un intermediario entre ellas, como una interfaz o una clase abstracta para reutilizar su código.

Veamos un ejemplo: Tenemos una clase User que necesita hacer registros de algún tipo de evento o acción (por ejemplo, hacer un registro de algún archivo o un registro en una base de datos). ¿Cómo aplicamos el principio?



Para hacerlo, se creó una interfaz Logger, que será nuestra abstracción. Luego creamos dos clases FileLogger y DatabaseLogger que implementan la interfaz. Estas clases serán los módulos de bajo nivel, mientras que a la clase User, nuestro módulo de alto nivel, le inyectamos la abstracción (Logger) por medio del constructor.

Esto ayuda a que la clase de alto nivel (User) reutilice código de todas las clases que implementen la abstracción (Logger). Si el usuario quiere hacer un registro en la base de datos, va a poder utilizar DatabaseLogger, pero si el usuario quiere registrar un archivo podrá utilizar FileLogger cuando sea necesario.

Ninguna clase depende de la otra, solo de la interfaz.


En resumen, los principios SOLID sirven para:

  • Mejorar la modularidad del código y facilitar la reutilización de componentes.
  • Favorecer el mantenimiento del software a medida que cambian los requisitos.
  • Reducir el acoplamiento para que el código sea más flexible y resistente a cambios.
  • Fomentar buenas prácticas de diseño como el uso de interfaces y la inyección de dependencias.
  • Ayudar a crear sistemas de software más escalables y sostenibles a lo largo del tiempo.


Espero que este artículo haya sido útil para conocer y aplicar los principios SOLID en tus proyectos, así como para seguir aprendiendo buenas prácticas para tu código.

¡Buena suerte y muchos éxitos!

💡
Las opiniones y comentarios emitidos en este artículo son propiedad única de su autor y no necesariamente representan el punto de vista de Listopro.

Listopro Community da la bienvenida a todas las razas, etnias, nacionalidades, credos, géneros, orientaciones, puntos de vista e ideologías, siempre y cuando promuevan la diversidad, la equidad, la inclusión y el crecimiento profesional de los profesionales en tecnología.