Cuándo usar una clase abstracta frente a una interfaz en C #

Al diseñar aplicaciones, es importante saber cuándo usar una clase abstracta y cuándo usar una interfaz. Aunque las clases e interfaces abstractas parecen similares en algunos aspectos, existen diferencias clave que determinarán cuál es la mejor opción para lo que está tratando de lograr. En esta publicación de blog, discutiré esas diferencias y cómo decidir cuándo usar cuál.

La respuesta corta: una clase abstracta le permite crear funciones que las subclases pueden implementar o anular. Una interfaz solo le permite definir la funcionalidad, no implementarla. Y mientras que una clase solo puede extender una clase abstracta, puede aprovechar múltiples interfaces. 

Explicación de la clase abstracta de C #

Una clase abstracta es un tipo especial de clase que no se puede instanciar. Una clase abstracta está diseñada para ser heredada por subclases que implementan o anulan sus métodos. En otras palabras, las clases abstractas se implementan parcialmente o no se implementan en absoluto. Puede tener funcionalidad en su clase abstracta; los métodos en una clase abstracta pueden ser tanto abstractos como concretos. Una clase abstracta puede tener constructores; esta es una de las principales diferencias entre una clase abstracta y una interfaz. Puede aprovechar las clases abstractas para diseñar componentes y especificar algún nivel de funcionalidad común que deben implementar las clases derivadas.

Explicación de la interfaz de C #

Una interfaz es básicamente un contrato, no tiene ninguna implementación. Una interfaz solo puede contener declaraciones de métodos; no puede contener definiciones de métodos. Tampoco puede tener datos de miembros en una interfaz. Mientras que una clase abstracta puede contener definiciones de métodos, campos y constructores, una interfaz solo puede tener declaraciones de eventos, métodos y propiedades. Los métodos declarados en una interfaz deben ser implementados por las clases que implementan la interfaz. Tenga en cuenta que una clase puede implementar más de una interfaz pero ampliar solo una clase. La clase que implementa la interfaz debe implementar todos sus miembros. Como una clase abstracta, no se puede crear una instancia de una interfaz.

¿Debería usar una clase abstracta o una interfaz?

Las clases abstractas le brindan la flexibilidad de tener ciertos métodos concretos y algunos otros métodos que las clases derivadas deberían implementar. Por el contrario, si usa interfaces, necesitaría implementar todos los métodos en la clase que extiende la interfaz. Una clase abstracta es una buena opción si tiene planes para una expansión futura, es decir, si es probable una expansión futura en la jerarquía de clases. Si desea brindar soporte para futuras expansiones al usar interfaces, deberá extender la interfaz y crear una nueva.

En una nota diferente, es fácil agregar una nueva interfaz a la jerarquía si es necesario. Sin embargo, si ya tiene una clase abstracta en su jerarquía, no puede agregar otra, es decir, puede agregar una clase abstracta solo si no hay ninguna disponible. Debe utilizar una interfaz si desea un contrato sobre algún comportamiento o funcionalidad. No debe utilizar una interfaz si necesita escribir el mismo código para los métodos de la interfaz. En este caso, debe usar una clase abstracta, definir el método una vez y reutilizarlo según sea necesario. Utilice interfaces para desacoplar el código de su aplicación de implementaciones específicas de la misma, o para restringir el acceso a miembros de cierto tipo.

Como dice la documentación de interfaces de Microsoft:

Al utilizar interfaces, puede, por ejemplo, incluir el comportamiento de varias fuentes en una clase. Esa capacidad es importante en C # porque el lenguaje no admite la herencia múltiple de clases. Además, debe usar una interfaz si desea simular la herencia de estructuras, porque en realidad no pueden heredar de otra estructura o clase.

Implementaciones de interfaz implícitas y explícitas

Las interfaces se pueden implementar implícita o explícitamente. Permítanme explicar en qué se diferencian estas dos implementaciones. Considere una interfaz llamada IBusinessLogic.

interfaz pública IBusinessLogic

{

   void Initialize ();

}

La siguiente clase llamada BusinessLogicimplementa la IBusinessLogicinterfaz.

clase pública BusinessLogic: IBusinessLogic

{

   public void Initialize ()

   {

       // Algún código

   }

}

Puede crear una instancia de la BusinessLogicclase explícitamente y luego llamar al Initialize()método como se muestra a continuación.

 IBusinessLogic businessLogic = new BusinessLogic ();

businessLogic.Initialize ();

El siguiente fragmento de código ilustra cómo puede implementar la IBusinessLogicinterfaz implícitamente.

clase pública BusinessLogic: IBusinessLogic

{

   void IBusinessLogic.Initialize ()

   {

   }

}

Ahora puede invocar el Initialize()método de la misma manera usando una referencia a la IBusinessLogicinterfaz. La diferencia entre los dos enfoques es que cuando implementas la interfaz explícitamente en tu clase, estás limitado a invocar un método de tu interfaz usando una referencia a la interfaz solamente. Por lo tanto, el siguiente fragmento de código no funcionaría, es decir, no se compilaría.

 BusinessLogic businessLogic = new BusinessLogic ();

businessLogic.Initialize ();

Cómo hacer más en C #:

  • Cuándo usar una clase abstracta frente a una interfaz en C #
  • Cómo trabajar con AutoMapper en C #
  • Cómo usar expresiones lambda en C #
  • Cómo trabajar con delegados Action, Func y Predicate en C #
  • Cómo trabajar con delegados en C #
  • Cómo implementar un registrador simple en C #
  • Cómo trabajar con atributos en C #
  • Cómo trabajar con log4net en C #
  • Cómo implementar el patrón de diseño del repositorio en C #
  • Cómo trabajar con la reflexión en C #
  • Cómo trabajar con filesystemwatcher en C #
  • Cómo realizar la inicialización diferida en C #
  • Cómo trabajar con MSMQ en C #
  • Cómo trabajar con métodos de extensión en C #
  • Cómo usar expresiones lambda en C #
  • Cuándo usar la palabra clave volátil en C #
  • Cómo usar la palabra clave yield en C #
  • Cómo implementar polimorfismo en C #
  • Cómo construir su propio programador de tareas en C #
  • Cómo trabajar con RabbitMQ en C #
  • Cómo trabajar con una tupla en C #
  • Explorando métodos virtuales y abstractos en C #