DEV Community

Cover image for De POO a SOLID explicado con Pokémon - Los cinco principios de SOLID
Jorge Méndez Ortega
Jorge Méndez Ortega

Posted on • Originally published at Medium

De POO a SOLID explicado con Pokémon - Los cinco principios de SOLID

GUÍA PARA ENTENDER LOS CINCO PRINCIPIOS DE SOLID.

JavaScript — Los cinco principios de SOLID

Genial estamos por terminar nuestra aventura Pokémon, finalmente veremos los cinco principios de SOLID, para poder llegar hasta este punto fue necesario pasar los siguientes retos.

📕 El paradigma de la Programación Orientada a Objetos
📗 Los cuatro principios de la Programación Orientada a Objetos

Si seguiste el tema desde el primer artículo deja decirte gracias 👏, regresando al tema que nos compete y posible mente la pregunta que te estés realizando al igual que yo es, pero ¿Que son los cinco principios de SOLID?

📝 Nota: Para entender los principios de SOLID es recomendable tener bases de los temas anteriores.


Pero, 🤔 ¿Qué son los principios de SOLID?

Es una serie de cinco reglas o principios que son aplicados en la POO cuyas iniciales dan como resultado el acrónimo SOLID este nombre es definido por Michael Feathers el cual hace referencia a los principios definidos por Robert C. Martín (Tío Bob) y Barbara Liskov.

Aplicar y conocer dichos principios tiene como consecuencia un desarrollo.

Fig. 1: Beneficios de SOLID.

En términos más generales se puede conseguir un mejor diseño de arquitectura y un código de mayor calidad, cada una de las letras de SOLID hace referencia a uno de sus principios.

Fig.2: El acrónimo de SOLID.

Los principios de SOLID no solo son aplicables a POO también son aplicables en Funciones (Programación funcional), pero es muy común verlo aplicado en POO, Estos principios son aplicables a cualquier lenguaje de programación.

🔖 Nota: Todos los ejemplos de código utilizados están basados en JavaScript usando las especificaciones más actuales hasta el momento.


📕S: Single Responsability Principle / Principio de Responsabilidad Única

Fig. 3: Single responsibility principle o Principio de responsabilidad única.

Una Clase solo debe tener solo una razón para cambiar, esto quiere decir que una clase solo debe contar con una sola responsabilidad.

Si una Clase contara con múltiples responsabilidades esto puede implicar que al realizar un cambio de alguna de ellas puede tener como consecuencia la modificación de otras responsabilidades lo que aumenta la posibilidad de incluir errores y poder afectar otras partes del sistema sin saberlo.

🔖 Nota: Single Responsability Principle **también se conoce como SRP** por sus siglas en ingles.

Interesante, pero generemos un ejemplo utilizando la vieja confiable Clase Pokémon.

Como podemos apreciar el ejemplo anterior no está aplica SRP ya que la Clase **consta de más de una **responsabilidad.

Fig. 5: Problemas de la clase Pokémon.

Al contar con múltiples responsabilidades se complica aplicar cambios ya que es posible que insertemos un error porque hacer un cambio de alguna responsabilidad, podría afectar a otras sin que nosotros lo sepamos, es momento de aplicar SRP.

Aplicando SRP vemos que entra en juego una nueva clase llamada DataBasela cual es encarga de manipular la Base de datos y por otro lado la Clase Pokemonsolo se encarga de definir nuevos Pokémons, de esta manera cada Clasetiene una responsabilidad además podemos conseguir una alta cohesión.

alta cohesión: Se refiere a la media que módulos de un sistema tiene una sola responsabilidad.


📗O: Open-Closed Principle/ Principio de Abierto-Cerrado

Fig. 7: Open-closed principle/ Principio de abierto-cerrado

Una entidad de SoftWare tiene que estar abierta para su extensión, pero cerrada para su modificación. Lo que establece este principio es que siempre que se desee realizar un cambio o nueva característica, se tendría que agregar código nuevo en lugar de modificar el existente.

Si una se desea que una Clase realice más funciones, lo ideal es extender las funcionalidades ya existentes y no modificarlas.

🔖 Nota: Open Closed Principle también se conoce como OCP por sus siglas en ingles.

Nuevamente utilizaremos la vieja confiable Clase Pokémon, para generar el ejemplo.

Como podemos apreciar el ejemplo anterior no está aplica OCP ya que la Clase ProcessAtack está abierta para recibir nuevos cambios.

Fig. 8: Problemas de la clase ProcessAttack.

Al momento de que nuestra la Clase está abierta a recibir nuevos cambios es posible que insertemos un error, porque estaríamos modificando código ya existente, para aplicar OCP utilizaremos el principio de Herencia y **Polimorfismo.

Al aplicar OCP en la Clase ProcessAttack lo primero que vemos es que ya no le importa saber el tipo de Pokémon solo le interesa el resultado del método attack para poder realizar la acción de ataque, con este nuevo diseño para poder agregar nuevos ataques por tipo de Pokémon solo es necesario crear nuevas SubClases de la Clase Pokémon, esto es un diseño mucho más robusto y fácil de extender.


📘 L: Liskov Substitution Principle/Principio de Sustitución de Liskov

Fig. 10: Liskov substitution principle / Principio de sustitución de Liskov

Puede que por su nombre asuste un poco 😱, pero en realidad es más sencillo de lo que parece. Este principio lo que dice es, Si S es un subtipo de T, los objetos de tipo T en un programa pueden reemplazarse por objetos de tipo** S** sin alterar ninguna de las propiedades del programa.

Este …ehm… como te digo que eso no suena tan sencillo como lo imaginaba.

De una manera más simple, el principio declara es que una, SubClase (clase hija) debe ser sustituible por su Super Clase (clase padre), si al hacer esto la clase falla estamos violando el principio🤯.

🔖 Nota: Liskov Substitution Principle también se conoce como LSP por sus siglas en ingles.

Nuevamente utilizaremos la vieja confiable Clase Pokémon, para generar el ejemplo.

El ejemplo anterior está rompiendo el principio LSP ya que como podemos apreciar la Sub-Clase (Charmander) tiene un comportamiento que difiere de la Clase-Padre (Pokémon),

Fig. 12: Problemas de la Clase Charmander

Al momento que una Sub-Clase no puede realizar las mismas acciones que la Clase-Padre esto puede provocar errores, para poder aplicar LSPutilizaremos el principio de Herencia.

Al aplicar LSP entra en juego PokemonFly que hereda de Pokémon y tiene el método canFly, de esta manera podemos definir quién puede volar y quien no, este principio es una advertencia de que el polimorfismo es poderoso, pero no siempre es fácil de aplica correctamente.


📙 I: Interface Segregation Principle/ Principio de Segregación de Interfaces

Fig. 13: Interface Segregation Principle/ Principio de Segregación de Interfaces

Los clientes no tienen que verse forzados a depender de interfaces que no utilicen, en otras palabras, cuando un Cliente A depende de una Clase que implementa una interfaz cuya funcionalidad el Cliente A no utilice, pero otros si, él Cliente A estará siendo afectados por los cambios que fuercen otros clientes.

Este principio suena muy similar a SPR ya que ambos están centrados en la cohesión de responsabilidades.

Este …ehm… pero en JavaScript no existen las interfaces genio.

Por lo que este principio no es aplicable estrictamente como otros, lo ideal es implementar pequeñas interfaces simuladas.

🔖 Nota: Interface Segregation Principle también se conoce como ISP por sus siglas en ingles.

Nuevamente utilizaremos la vieja confiable Clase Pokémon, para generar el ejemplo.

Como podemos apreciar el ejemplo anterior no está aplica ISP ya que la Clase Pokemon tiene métodos que no son aplicables en todos las SubClaseslas cuales se ven obligadas aplicar acepciones o comportamientos diferentes para los métodos que no utilizan.

Fig: 15: Problemas de la clase Pokémon.

Al momento de que nuestra la Clase consta de métodos que pueden o no aplicar a sus descendientes es muy fácil que insertemos errores, la solución para poder implementar ISP es necesario separar el código en pequeñas partes así de cada clase podrá usar los métodos que realmente utilice.

🔖 Nota: En JavaScript solo se puede tener una clase padre, por lo que la herencia múltiple de manera directa no es posible, para eso usaremos los mix-ins.

Al aplicar ISP entran en juego el manejo de interfaces, pero como sabemos en JavaScript por lo que implementamos Mix-ins con los cuales podremos simular un comportamiento parecido a las interfaces con lo que podremos agregar solo los métodos que realmente necesite nuestra Subclase.


📒 D: Dependency Inversion Principle / Principio de Inversión de Dependencia

Fig., 17:Dependency Inversion Principle / Principio de Inversión de Dependencia

Realmente este principio dicta dos puntos importantes los cuales son

Los módulos de alto nivel no deben depender de los módulos de bajo nivel, Ambos tiene que depender de abstracciones.

Las abstracciones no deben depender de los detalles. Los detalles deben depender de abstracciones.

Hay un momento puede que esto no suene tan sencillo inicialmente, pongamos en claro los términos utilizados.

  • Módulo de Alto Nivel (Clase): Clase con la que se ejecuta una acción utilizando una herramienta

  • Módulo de Bajo Nivel (Clase): La **herramienta necesaria para ejecutar la acción

  • Abstracción: Representa la interfaz que conecta a las 2 clases

  • Detalles: Cómo funciona la herramienta.

🔖 Nota: Dependency Inversion Principle tambiénse conoce como DIP por sus siglas en ingles.

En este ejemplo crearemos una clase llamada Pokedex ya que desde mi punto de vista es como el mejor ejemplo que se presta para la explicación.

Revisando el ejemplo podemos ver que la Clase Pokedex tiene una dependencia directa a ApiPokemon. por esta razón el principio de DIP no se aplica ya que una de las Clases tiene conocimiento de cómo se implementa ApiPokemon.

Fig. 19: Problemas de la clase Pokedex.

Para poder implementar DIP utilizaremos inyección de dependencias así la Clase Pokedex solo se encargará de solicitar data.

Al momento de realizar una inyección de Dependencias la clase Pokedex, eliminamos la dependencia que se tenía de la clase ApiPokemon, de esta manera cumpliríamos con el principio de DIP.

🔖 Nota: La implementación de DIP regular mente puedes se utiliza con interfaces en este caso podríamos haber usado mix-in.


Conclusiones

Como podemos ver cada uno de los principios de SOLID consigue un objetivo en concreto.

  • Principio de Responsabilidad Única:
    Su propósito es separar los comportamientos.

  • Principio Abierto/Cerrado:
    Su objetivo es ampliar el comportamiento de una clase sin modificar el comportamiento existente.

  • Principio de Sustitución de Liskov:
    **Su objetivo es aplicar coherencia entre clases.

  • Principio de Segregación de la Interfaz:
    **Su objetivo es dividir un conjunto de acciones en conjuntos más pequeños para ejecutar solo el conjunto de acciones que se requieren.

  • Principio de inversiones Dependencias:
    **Su objetivo es reducir la dependencia de una clase de alto nivel en la clase de bajo nivel mediante la introducción de una interfaz.

Por último, recordemos que SOLID solo es una herramienta que nos ayuda a escribir mejor código, por lo que hay que tomar en cuenta que no hay que caer en el uso excesivo de SOLID ya que puede que estos principios compliquen mucho el código si es así talvez solo sea necesario aplicar parte de estos.

Top comments (0)