3:12 0 0
Principios SOLID Open Close Principle

Principios SOLID Open Close Principle

  DrUalcman |  enero 72022

Single responsabilitie Principle [SRP]

Open/Close Principle [OCP]

Definición: Cada componente de un programa debe de estar abierto para ser extendido y cerrado para ser modificado.

Si la teoría esta toda muy bonita, pero ¿y que carajo quiere decir eso? Bueno vamos a intentar explicarlo lo más cencillo posible, pero la verdad que este es uno de los principio que más se me atraganta. Para algunas cosas es muy fácil de ver y comprender, pero luego cuando intentas analizar tus métodos o clases a ver si cumplen o si pueden cumplir este principio, no es tan fácil de llevar a cabo. Bueno vamos a ver en que consiste este principio.

La forma más fácil que veo de intentar explicarlo es, cuando estamos creando una clase o un método y vemos que podría ser utilizado, por decir algo, con un monton de si, si si, o con un cuando... o lo que es lo mismo, con un montón de if, if, fi o un switch. En éste momento es cuando nos debemos de parar y pensar si podría se mejor intentar buscar de aplicar este principio.

Creo que me lié, a ver, cada piza del programa, debe de poder extenderse, por ejmplo, pasándole otras piezas que le agregen funcionalidad, pero que no necesariamente me obligue a cambiar el código. Empecemos a ver algo de código, porque como he dicho, este es el principio que más se me atraganta. Voy a usar un ejemplo de los que yo veo super evidente y fácil de comprender este principio, pero luego aplicarlo, se complica, pero no para este ejemplo que voy a usar, es muy claro y fácil de entender, como en los entrenamientos que he asistido.

Otra curiosidad que tiene este principio, es que va muy de la mano del Single Responsabilitie Principle, que ya comente en mi blog pasado. Casi casi, uno no puede existir sin el otro, y lo vemás muy claro con el ejemplo que voy a poner para realizar un registro d eeventos.

Ejemplo que no cumple con OCP

Tenemos una clase que va a realizar un registro de lo que está ocurriendo. Inicialmente esta clase va a realizar 2 tipos de registro, uno a consola del programa y otro a la consola de programacion, es decir, este último sólo es para cuando se esta en modo de desarrollo.

public class LogService
{
enum LogType{
Console,
Debug
}

public void Register(string message, LogType type)
{
switch (type)
{
case type.Console:
WriteToConsole(message);
break;
case type.Debug:
WriteToDEbug(message);
break;
}
}

private WriteToConsole(string message) {
Console.WriteLine(message);
}

private WriteToDEbug(string message) {
Debug.WriteLine(message);
}
}

Como podeis apreciar, estamos utilizando un enumeral para definir que tipo de registro queremos realizar, y luego en función del la opción que elija el programador pues se llama a un método u otro dependiendo de la opción. Es aquí, como comentaba antes, donde podemos ver claramente que pasa si ahora nuestro requerimiento es, almacenar en una base de datos, por ejemplo. Debemos de agregar otra opción dentro del enumeral y un nuevo método para registrar en la base de datos. Listo, no es dificil, pero es aquí dónde no cumplimos con el principio de OCP, ¿Lo ves claro?

Además también es donde no cumplimos con el SRP, ese ya te dejo a ti que pienses el porqué tampoco se cumple este otro principio, y el porque estos dos principios sulen ir de la mano, para ciumplir con uno, como norma general, indirectamente cumples con el otro.

Veamos como quedaría esta clase respetando el OCP

Bueno, primero antes de ver código aclarar que podemos aplicar el OCP tango a nivel de clase como a nivel de método. Yo voy a ejemplarizarlo a nivel de clase, por seguir también respetando el SRP, ya que cuando se hace a nivel de método, casi, casi, que puedes pecar de no respetar el SRP por que vas a dar muchas responsabilidades a la clase.

public interface ILogEvent{
void Write(string message);
}

public class LogService
{
readonly ILogEvent Logger;

public LogService(ILogEvent logger) => Logger = logger;

public void Register(string message)
{
Logger.Write(message);
}
}

¡Pero que lino es programar! ¿Ha que ha quedado chulo? Ésta sería toda nuestra clase, nada más, y está abierta para extenderse pero cerrada para tener que ser modificada en caso de necesitar un nuevo log. Pero claro, hay un poco de trampa detrás de este poco código. Ésto es como ha queda la clase que realiza el registo, ¿pero realmente hace algo? Ella por sí sola no. Necesita que otra clase implemente el ILogEvent que será la que realmente muestre o registre el evento ocurrido, de nuevo respetamos indirectamente el SRP, mi responsabilidad es lanzar un registro, como se muestr o registre ya no es cosa mía. En el siguiente fragmente de código muestro 3 implementaciones, con los requerimientos que nos cambiaron cuando estamos haciendo la el trabajo.

public class WriteToConsole : ILogEvent {
    private Write(string message) {
        Console.WriteLine(message);
    }  
}  
public class WriteToDebug : ILogEvent {
    private Write(string message) {
        Debug.WriteLine(message);
    }  

public class WriteToDataBase : ILogEvent {
    private Write(string message) {
        SqlConnection con = new SqlConnection();
        con.Open();
        SqlCommand command = con.CreateCommand("INSERT INTO [...]");  //insert into a DB
    }  

Igual se puede ver que las clases para realizar la acción apenas tienen lineas de código. Esto es el lado oscuro de intentar hacer un código límpio y seguir las recomendaciones de los principios SOLID, que te llenas de clases, pero todas con poco código, de esta forma el código va convirtiéndose en algo más manejable y fácil de mantener. ¿Seguro? Aquí se podría tener un buen debate, pero bueno. Para gustos patrones jejeje.

Conclusiones

Bueno hasta aquí mi breve explicación e interpretación de lo que es Open/Close Principle. Espero que se haya entendido y que me comentéis que os parece. Dicifil de aplicar, fácil, es una tontería, lo que querais.

Liskov Substitutio Principle [LSP]

Interface Segregation Principle [ISP]

Dependency Inversion Principle [DIP]

0 Comentarios

 
 
 

Archivo