В некоторых рекомендациях указано, что вы должны использовать интерфейс, если хотите определить контракт для класса, где наследование не ясно (IDomesticated
) и наследование, когда класс является расширением другого (Cat : Mammal
, Snake : Reptile
), бывают случаи, когда (на мой взгляд) эти рекомендации входят в серое пространство.
Например, скажем, моя реализация была Cat : Pet
. Pet
- абстрактный класс. Должно ли быть расширено до Cat : Mammal, IDomesticated
, где Mammal
является абстрактным классом, а IDomesticated
является интерфейсом? Или я в конфликте с KISS/YAGNI (хотя я не уверен, будет ли в будущем класс Wolf
, который не сможет наследовать от Pet
)?
Переходя от метафорических Cat
и Pet
s, скажем, у меня есть некоторые классы, которые представляют источники для входящих данных. Все они должны каким-то образом реализовать ту же базу. Я мог бы реализовать некоторый общий код в абстрактном классе Source
и наследовать его. Я мог бы просто создать интерфейс ISource
(который мне кажется более "правильным" ) и повторно реализовать общий код в каждом классе (который менее интуитивно понятен). Наконец, я мог "взять пирог и съесть его", сделав как абстрактный класс, так и интерфейс. Что лучше?
В этих двух случаях возникают точки для использования только абстрактного класса, только интерфейса и использования как абстрактного класса, так и интерфейса. Являются ли эти все действительные выборы или существуют "правила", когда их нужно использовать над другим?
Я хотел бы пояснить, что "используя как абстрактный класс, так и интерфейс", который включает случай, когда они по существу представляют одно и то же (Source
и ISource
оба имеют одинаковые элементы), но класс добавляет общую функциональность, в то время как интерфейс указывает контракт.
Также стоит отметить, что этот вопрос в основном относится к языкам, которые не поддерживают множественное наследование (например,.NET и Java).