No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Conociendo el principio de abierto/cerrado

7/16
Recursos

¿Qué es el principio abierto-cerrado?

El principio abierto-cerrado, conocido en inglés como Open-Close Principle, es uno de los cinco principios SOLID fundamentales en el diseño de software, propuestos por Robert C. Martin. Este principio establece que un componente de un sistema debe estar abierto para ser extendido, pero cerrado para modificaciones. Es una regla esencial que permite la evolución del software sin comprometer la estabilidad del sistema.

  1. Extensibilidad: La idea es que el código debe poder ampliarse para agregar nuevas funcionalidades. Cuando se requiere un nuevo comportamiento, debería ser posible añadirlo sin tener que alterar el código existente.
  2. Proteger el código probado: Esto es crucial para asegurar que el código ya probado y validado no sea alterado, minimizando así los riesgos de introducir nuevos errores durante el proceso de expansión.

¿Cómo se aplica este principio en C#?

C# ofrece herramientas y técnicas que permiten aplicar el principio abierto-cerrado de forma efectiva. Aquí te damos algunas claves esenciales para ello:

Uso de clases abstractas e interfaces

En C#, las clases abstractas e interfaces proporcionan una manera de extender funcionalidades sin alterar el código existente:

  • Clases abstractas: Estas se utilizan como modelos que otras clases pueden heredar. Permiten definir métodos que las subclases deben implementar, promoviendo así la extensión sin modificar la lógica base.

    public abstract class Employee
    {
        public abstract void CalculateSalary();
    }
    
    public class FullTimeEmployee : Employee
    {
        public override void CalculateSalary()
        {
            // Implementación del cálculo para empleados a tiempo completo
        }
    }
    
    public class PartTimeEmployee : Employee
    {
        public override void CalculateSalary()
        {
            // Implementación del cálculo para empleados a medio tiempo
        }
    }
    
  • Interfaces: C# no soporta la herencia múltiple, pero las interfaces ofrecen una forma poderosa de añadir capacidades a las clases sin cambiar su estructura existente. Permiten que una clase implemente múltiples interfaces, cada una centrada en una responsabilidad específica.

Ejemplo práctico con acceso a datos

Un ejemplo claro de cómo aplicar este principio se muestra en la arquitectura de acceso a datos. Imagina un sistema que requiere diferentes tipos de interacciones con una base de datos. Puedes utilizar interfaces para dividir responsabilidades:

  • Una interfaz para manejar la conexión a la base de datos.
  • Otra interfaz para consultas (iQuery).
  • Una interfaz adicional para operaciones de eliminación (iDelete).

Cada componente del acceso a datos implementará solo las interfaces que necesite, asegurando que nuevos comportamientos pueden ser añadidos por medio de nuevas interfaces sin tocar el código existente.

public interface IDataConnection
{
    void Connect();
}

public interface IQuery
{
    void ExecuteQuery(string query);
}

public interface IDelete
{
    void DeleteItem(int id);
}

public class DataAccess : IDataConnection, IQuery, IDelete
{
    public void Connect()
    {
        // Código para conectar
    }

    public void ExecuteQuery(string query)
    {
        // Código para ejecutar consulta
    }

    public void DeleteItem(int id)
    {
        // Código para eliminar item
    }
}

¿Por qué es esencial evitar la herencia múltiple en C#?

A diferencia de otros lenguajes, en C#, no se permite la herencia múltiple de clases por las complejidades que esto podría introducir en el modelo de objetos. Sin embargo, las interfaces proporcionan una solución flexible y precisa para implementar múltiples comportamientos. Esto permite diseñar sistemas que son susceptibles de evolución y extensión, sin el riesgo de complicaciones que vendrían con la modificación directa del código existente.

Implementación de un caso práctico: EmployeeContractor

En el proyecto de clase ejemplo, donde existen clases de empleados a tiempo completo (EmployeeFullTime) y a tiempo parcial (EmployeePartTime), se rellena la necesidad de extender funcionalidad para incluir empleados contratistas sin cambiar las clases existentes. Esto se logra definiendo una nueva clase que hereda de la clase base.

public class EmployeeContractor : Employee
{
    // Implementación para empleados contratistas
}

Así, siguiendo el principio abierto-cerrado, se añade funcionalidad asegurando la integridad del sistema y preparando el terreno para futuras extensiones. La implementación respetuosa de este principio fomenta un diseño arquitectónicamente robusto y escalable.

Aportes 6

Preguntas 1

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

Hasta ahora los contenidos del maestro Miguel me han parecido excelentes. Cómo siempre explican muy bien la información y es un contenido supremamente condensado que cada clase si se le presta la atención requerida, toma más del tiempo que es ver el video.

Por otro lado, me agradaría que existiera un curso que nos permitiera ver todas las bondades del POO en C#, ya que, en muchas explicaciones se habla de Interfaces, clases abstractas que, actualmente no he encontrado información en C# que hable sobre estos temas dentro de PLATZI. Si existe y me quiere colaborar mostrándome el curso que debería de ver, se los agradezco (Ya realicé varios cursos de C#, pero, ninguno habla sobre genéricos, clases abstractas o interfaces)

En C#, puedes seguir el principio OCP siguiendo las siguientes pautas:

  • Utiliza la herencia y la implementación de interfaces: Define interfaces y clases base que sean genéricas y reutilizables. Luego, crea clases derivadas o implementaciones concretas para extender el comportamiento de estas clases base. De esta manera, puedes agregar nuevas funcionalidades sin modificar las clases existentes.

  • Aplica el polimorfismo: Utiliza el polimorfismo para tratar diferentes objetos de manera uniforme. Esto te permitirá agregar nuevas clases que implementen una interfaz común o hereden de una clase base, sin tener que modificar el código existente.

  • Utiliza inyección de dependencias: Diseña tus clases para que dependan de abstracciones en lugar de implementaciones concretas. Luego, utiliza la inyección de dependencias para proporcionar las implementaciones necesarias en tiempo de ejecución. Esto permitirá que el comportamiento de una clase pueda ser extendido sin modificarla directamente.

  • Utiliza patrones de diseño como el patrón Strategy o el patrón Decorator: Estos patrones permiten agregar o cambiar comportamientos en tiempo de ejecución sin modificar las clases existentes.

  • Aplica el principio de inversión de dependencia: Diseña tus clases para depender de abstracciones en lugar de detalles concretos. Esto implica que las clases de nivel superior dependan de abstracciones, mientras que los detalles concretos sean dependencias de nivel inferior. De esta manera, las clases de nivel superior permanecerán cerradas para modificaciones y abiertas para extensiones.

Vayan al sitio web de Bertrand Meyer aquí, está muy bueno o cómo decimos en Medallo, una chimba.

Acá una cita de lo que me fascinó.

The use of “statement” to mean “instruction” obscures a fundamental distinction of software engineering: the duality between specification and implementation.

/

Esto me enseñó que debemos diferenciar entre “Statement” o declaración en español e instrucción “Instruction”. Ya que la programación ofrece soluciones para los problemas y para lograr hacerlo es necesario ofrecer como resultado dos insumos: Una declaración del problema y luego la invención que (el código) implementa la invención.

/

Mi recomendación es que sigas aprendiendo del tema y pongas en duda mi interpretación.

excelente explicacion de conceptos solidn