Quando usar interfaces ou classes abstratas? Quando usar os dois?
Embora algumas diretrizes indiquem que você deve usar uma interface quando quiser definir um contrato para uma classe em que a herança não esteja clara (IDomesticated
) e herança quando a classe é uma extensão de outra (Cat : Mammal
, Snake : Reptile
), há casos em que (na minha opinião) essas diretrizes entram em uma área cinza.
Por exemplo, digamos que minha implementação foiCat : Pet
. Pet
é uma classe abstrata. Isso deve ser expandido paraCat : Mammal, IDomesticated
OndeMammal
é uma classe abstrata eIDomesticated
é uma interface? Ou estou em conflito com oBEIJO/YAGNI princípios básicos (embora eu não tenha certeza se haveráWolf
classe no futuro, que não seria capaz de herdarPet
)
Afastando-se do metafóricoCat
areiaPet
s, digamos que eu tenha algumas classes que representam fontes de dados recebidos. Todos eles precisam implementar a mesma base de alguma forma. Eu poderia implementar algum código genérico em um resumoSource
classe e herda dele. Eu também poderia apenas fazer umaISource
interface (que se sente mais "certo" para mim) e re-implementar o código genérico em cada classe (o que é menos intuitivo). Finalmente, eu poderia "ter o bolo e comê-lo" fazendo a classe abstrata e a interface. O que é melhor?
Esses dois casos trazem pontos para usar apenas uma classe abstrata, apenas uma interface e usando uma classe abstrata e uma interface. Todas essas escolhas são válidas ou há "regras" para quando uma deve ser usada em detrimento de outra?
Gostaria de esclarecer que "usando tanto uma classe abstrata e uma interface", que inclui o caso quando eles representam essencialmente a mesma coisa (Source
eISource
ambos têm os mesmos membros), mas a classe adiciona funcionalidade genérica enquanto a interface especifica o contrato.
Também vale a pena notar que esta questão é principalmente para linguagens que não suportam herança múltipla (como .NET e Java).