¿Cuándo usar interfaces o clases abstractas? ¿Cuándo usar ambos?

Si bien ciertas pautas indican que debe usar una interfaz cuando desee definir un contrato para una clase en la que la herencia no está clara (IDomesticated) y la herencia cuando la clase es una extensión de otra (Cat : Mammal, Snake : Reptile), hay casos en que (en mi opinión) estas pautas entran en un área gris.

Por ejemplo, digamos que mi implementación fueCat : Pet. Pet Es una clase abstracta. Si eso se expandiera aCat : Mammal, IDomesticated dóndeMammal es una clase abstracta yIDomesticated es una interfaz? ¿O estoy en conflicto con elBESO/YAGNI principios (aunque no estoy seguro de si habrá unaWolf clase en el futuro, que no sería capaz de heredar dePet)?

Alejándose de lo metafórico.Cats yPetS, digamos que tengo algunas clases que representan fuentes para los datos entrantes. Todos necesitan implementar la misma base de alguna manera. Podría implementar algún código genérico en un resumen.Source Clase y heredar de ella. También podría hacer unISource Interfaz (que me parece más "correcta") y reimplementar el código genérico en cada clase (que es menos intuitivo). Finalmente, podría "tener el pastel y comerlo" haciendo la clase abstracta y la interfaz. Que es lo mejor

Estos dos casos muestran puntos por usar solo una clase abstracta, solo una interfaz y usar tanto una clase abstracta como una interfaz. ¿Son todas estas opciones válidas, o hay "reglas" para cuando una debe usarse sobre otra?

Me gustaría aclarar que al "usar tanto una clase abstracta como una interfaz" que incluye el caso cuando esencialmente representan la misma cosa (Source yISource ambos tienen los mismos miembros), pero la clase agrega funcionalidad genérica mientras que la interfaz especifica el contrato.

También vale la pena señalar que esta pregunta es principalmente para idiomas que no admiten la herencia múltiple (como .NET y Java).

Respuestas a la pregunta(7)

Su respuesta a la pregunta