Kiedy używać interfejsów lub klas abstrakcyjnych? Kiedy używać obu?

Podczas gdy niektóre wytyczne mówią, że należy użyć interfejsu, aby zdefiniować umowę dla klasy, w której dziedziczenie nie jest jasne (IDomesticated) i dziedziczenia, gdy klasa jest rozszerzeniem innej (Cat : Mammal, Snake : Reptile), zdarzają się przypadki, kiedy (moim zdaniem) te wytyczne wchodzą w szary obszar.

Powiedzmy na przykład, że moje wdrożenie byłoCat : Pet. Pet jest klasą abstrakcyjną. Powinny zostać rozszerzone naCat : Mammal, IDomesticated gdzieMammal jest klasą abstrakcyjną iIDomesticated to jest interfejs? Czy jestem w konflikcie zPOCAŁUNEK/YAGNI zasady (nawet jeśli nie jestem pewien, czy będzieWolf klasa w przyszłości, która nie byłaby w stanie dziedziczyć po niejPet)?

Odchodząc od metaforycznegoCats iPets, powiedzmy, że mam kilka klas reprezentujących źródła danych przychodzących. Wszyscy muszą jakoś wdrożyć tę samą bazę. Mógłbym zaimplementować jakiś ogólny kod w abstrakcjiSource klasa i dziedziczę po niej. Mógłbym też po prostu zrobićISource interfejs (który jest dla mnie bardziej „właściwy”) i ponownie implementuje kod ogólny w każdej klasie (co jest mniej intuicyjne). Wreszcie mogłem „zjeść ciasto i zjeść je”, tworząc zarówno klasę abstrakcyjną, jak i interfejs. Co jest najlepsze?

Te dwa przypadki wywołują punkty za używanie tylko klasy abstrakcyjnej, tylko interfejsu i używanie zarówno klasy abstrakcyjnej, jak i interfejsu. Czy są to wszystkie ważne wybory, czy też istnieją „zasady”, kiedy ktoś powinien być używany nad innym?

Chciałbym wyjaśnić, że „używając zarówno klasy abstrakcyjnej, jak i interfejsu”, która obejmuje przypadek, gdy zasadniczo reprezentują to samo (Source iISource oba mają tych samych członków), ale klasa dodaje ogólną funkcjonalność, podczas gdy interfejs określa umowę.

Warto również zauważyć, że to pytanie dotyczy głównie języków, które nie obsługują wielokrotnego dziedziczenia (takich jak .NET i Java).

questionAnswers(7)

yourAnswerToTheQuestion