Interfaz vs clase base
¿Cuándo debo usar una interfaz y cuándo debo usar una clase base?
¿Debería ser siempre una interfaz si no quiero definir una implementación base de los métodos?
Si tengo una clase de Perros y Gatos. ¿Por qué querría implementar IPet en lugar de PetBase? Puedo entender tener interfaces para ISheds o IBarks (¿IMakesNoise?), porque se pueden colocar mascota por mascota, pero no entiendo cuál usar para una mascota genérica.
Tomemos su ejemplo de una clase Perro y Gato e ilustremos usando C#:
Tanto un perro como un gato son animales, específicamente, mamíferos cuadrúpedos (los animales son demasiado generales). Supongamos que tienes una clase abstracta Mamífero, para ambos:
public abstract class Mammal
Esta clase base probablemente tendrá métodos predeterminados como:
- Alimentar
- Compañero
Todos ellos son comportamientos que tienen más o menos la misma implementación entre ambas especies. Para definir esto tendrás:
public class Dog : Mammal
public class Cat : Mammal
Ahora supongamos que hay otros mamíferos, que normalmente veremos en un zoológico:
public class Giraffe : Mammal
public class Rhinoceros : Mammal
public class Hippopotamus : Mammal
Esto seguirá siendo válido porque el núcleo de la funcionalidad Feed()
seguirá Mate()
siendo el mismo.
Sin embargo, las jirafas, los rinocerontes y los hipopótamos no son exactamente animales de los que puedas convertirlos en mascotas. Ahí es donde será útil una interfaz:
public interface IPettable
{
IList<Trick> Tricks{get; set;}
void Bathe();
void Train(Trick t);
}
La ejecución del contrato anterior no será la misma entre un gato y un perro; poner sus implementaciones en una clase abstracta para heredar será una mala idea.
Tus definiciones de Perro y Gato ahora deberían verse así:
public class Dog : Mammal, IPettable
public class Cat : Mammal, IPettable
Teóricamente puedes anularlos desde una clase base superior, pero esencialmente una interfaz te permite agregar solo las cosas que necesitas a una clase sin necesidad de herencia.
En consecuencia, debido a que generalmente solo puede heredar de una clase abstracta (en la mayoría de los lenguajes OO de tipo estático, es decir... las excepciones incluyen C++) pero puede implementar múltiples interfaces, le permite construir objetos estrictamente según sea necesario .
Bueno, el mismo Josh Bloch dijo en Effective Java 2d :
Prefiero interfaces a clases abstractas
Algunos puntos principales:
Las clases existentes se pueden adaptar fácilmente para implementar una nueva interfaz . Todo lo que tienes que hacer es agregar los métodos requeridos si aún no existen y agregar una cláusula de implementos a la declaración de clase.
Las interfaces son ideales para definir mixins . En términos generales, un mixin es un tipo que una clase puede implementar además de su "tipo primario" para declarar que proporciona algún comportamiento opcional. Por ejemplo, Comparable es una interfaz mixin que permite a una clase declarar que sus instancias están ordenadas con respecto a otros objetos mutuamente comparables.
Las interfaces permiten la construcción de frameworks de tipo no jerárquico . Las jerarquías de tipos son excelentes para organizar algunas cosas, pero otras no caen claramente en una jerarquía rígida.
Las interfaces permiten mejoras de funcionalidad potentes y seguras a través del lenguaje de clase contenedora. Si usa clases abstractas para definir tipos, deja al programador que desea agregar funcionalidad sin otra alternativa que usar la herencia.
Además, puede combinar las virtudes de las interfaces y las clases abstractas proporcionando una clase de implementación esquelética abstracta para cada interfaz no trivial que exporte.
Por otro lado, las interfaces son muy difíciles de evolucionar. Si agrega un método a una interfaz, se romperán todas sus implementaciones.
PD.: Compra el libro. Es mucho más detallado.
Las interfaces y las clases base representan dos formas diferentes de relaciones.
La herencia (clases base) representa una relación "es-un". Por ejemplo, un perro o un gato "es una" mascota. Esta relación siempre representa el (único) propósito de la clase (en combinación con el "principio de responsabilidad única" ).
Las interfaces , por otro lado, representan características adicionales de una clase. Yo lo llamaría una relación "es", como en " Foo
es desechable", de ahí la IDisposable
interfaz en C#.
El estilo moderno es definir IPet y PetBase.
La ventaja de la interfaz es que otro código puede utilizarla sin ningún vínculo con otro código ejecutable. Completamente "limpio". También se pueden mezclar interfaces.
Pero las clases base son útiles para implementaciones simples y utilidades comunes. Por lo tanto, proporcione también una clase base abstracta para ahorrar tiempo y código.