Una mirada diferente a los 5 principios SOLID
Los principios SOLID son algunas de las reglas más antiguas del mundo del software. Nos permiten escribir código mantenible, legible y reutilizable. En este texto, estoy tratando de lograr un ejemplo de la vida real, obedeciendo los principios de SOLID.
1. Responsabilidad única
Cada clase debe tener un solo propósito y no estar llena de funcionalidades excesivas. Considere el siguiente ejemplo:

Esta clase se implementa para cifrar contraseñas, como su nombre lo indica. No debe ser su responsabilidad guardarlos en la base de datos. Cada clase debe tener una sola responsabilidad que cumplir.
No debería haber ” clases de dios” que tengan una amplia variedad de funcionalidades que tengan mucho que lograr. En su lugar, deberíamos escribir nuestras clases de la forma más modular posible. Implementar la operación de guardar en otra clase.
2. Principio abierto-cerrado
Las clases deben estar abiertas para extensión, cerradas para modificación.
En otras palabras, no debería tener que volver a escribir una clase existente para implementar nuevas funciones.
Continuemos con nuestro ejemplo de hasher de contraseña. Supongamos que queremos que nuestra clase pueda hacer hash con una variedad de opciones de algoritmo.

Si implementáramos de esta manera, romperíamos la O en SOLID tan mal. Cada vez que se implementa un nuevo algoritmo, necesitamos modificar la clase existente y se ve feo.
Gracias a OOP, tenemos abstracción. Deberíamos hacer de nuestra clase inicial una clase de interfaz/abstracta e implementar los algoritmos en las clases concretas.

El orden de las clases puede resultar extraño, desafortunadamente Gist las ordena alfabéticamente, cuando se juntan.
De esta forma, podemos agregar nuevos algoritmos sin tocar el código base existente.
3. Principio de sustitución de Liskov
Una subclase debería poder cumplir con cada característica de su clase principal y podría tratarse como su clase principal.
Para demostrar nuestro ejemplo, vamos a crear las clases de modelo (datos) para usar nuestros algoritmos hash.
E implementamos lo mismo para otras codificaciones…
Para cumplir con la regla de Liskov, cada extensión de Hashed debe usar una implementación válida de la función hash y devolver un hash.

Por ejemplo, si extendemos la clase Hashed con una clase llamada “NoHash” que usa una implementación que devuelve exactamente la misma contraseña sin ninguna codificación, se romperá la regla, ya que se espera que una subclase de Hashed tenga un valor hash de la contraseña.
4. Principio de segregación de interfaces
Las interfaces no deberían obligar a las clases a implementar lo que no pueden hacer. Las interfaces grandes deben dividirse en pequeñas.
Considere que agregamos la función de decodificación a la interfaz.

Esto violaría esta ley ya que uno de nuestros algoritmos, el SHA256, no es prácticamente descifrable (es una función unidireccional). En su lugar, podemos agregar otra interfaz a las clases aplicables para implementar su algoritmo de decodificación.

5. Principio de inversión de dependencia
Los componentes deberían depender de abstracciones, no de concreciones.
Disponemos de un servicio de contraseñas como el siguiente:

Violamos el principio ya que acoplamos estrechamente el
Vamos a desacoplarlos y dejar que el cliente inyecte el servicio hasher necesario con el constructor.

Mucho mejor. Podemos cambiar fácilmente el algoritmo hash. Nuestro servicio no se preocupa por el algoritmo, depende del cliente elegirlo. No dependemos de la implementación concreta, sino de la abstracción.