Когда использовать интерфейсы или абстрактные классы? Когда использовать оба?

Хотя в некоторых рекомендациях говорится, что вы должны использовать интерфейс, если вы хотите определить контракт для класса, в котором наследование неясно (IDomesticated) и наследование, когда класс является продолжением другого (Cat : Mammal, Snake : Reptile), бывают случаи, когда (по моему мнению) эти рекомендации попадают в серую зону.

Например, скажем, моя реализация былаCat : Pet. Pet это абстрактный класс. Должно ли это быть расширено доCat : Mammal, IDomesticated гдеMammal абстрактный класс иIDomesticated такое интерфейс? Или я в конфликте сПОЦЕЛУЙ/YAGNI принципы (хотя я не уверен, будет лиWolf класс в будущем, который не сможет унаследовать отPet)?

Отойдя от метафорическогоCatс иPets, скажем, у меня есть несколько классов, которые представляют источники для входящих данных. Им всем нужно как-то реализовать одну и ту же базу. Я мог бы реализовать некоторый общий код в абстрактномSource класс и наследовать от него. Я также мог бы просто сделатьISource интерфейс (который кажется мне более «правильным») и повторно реализовать универсальный код в каждом классе (который менее интуитивно понятен). Наконец, я мог бы «съесть торт и съесть его». делая как абстрактный класс, так и интерфейс. Что лучше?

Эти два случая поднимают вопрос об использовании только абстрактного класса, только интерфейса и как абстрактного класса, так и интерфейса. Это все действительные варианты или есть «правила»? когда один должен быть использован поверх другого?

Я хотел бы пояснить это, используя «абстрактный класс и интерфейс»; это включает в себя случай, когда они по существу представляют собой одно и то же (Source а такжеISource оба имеют одинаковых членов), но класс добавляет общие функциональные возможности, в то время как интерфейс определяет контракт.

Также стоит отметить, что этот вопрос в основном относится к языкам, которые не поддерживают множественное наследование (например, .NET и Java).

Ответы на вопрос(7)

Ваш ответ на вопрос