Есть ли преимущество в наличии как абстрактного класса, так и интерфейса?

StackOverflow https://stackoverflow.com/questions/267045

Вопрос

Я начал с универсального интерфейса под названием ILogin.Интерфейсы требуют, чтобы вы реализовали два свойства:Идентификатор пользователя и пароль.У меня есть много классов типа login, которые реализуют этот интерфейс.По мере того как мой проект рос и расширялся, я обнаружил, что многие классы повторяют идентификатор пользователя и код пароля.Теперь я решаю, что мне нужен базовый класс входа в систему.

Правильно ли создавать абстрактный базовый класс Login, который реализует интерфейс ILogin и имеет все мои конкретные классы, просто наследующие от абстрактного класса и переопределяющие при необходимости?Изначально я думал, что с этим не возникнет никаких проблем.Затем я начал думать, что ILogin, вероятно, не нужен, потому что он, скорее всего, будет реализован только моим абстрактным классом.

Есть ли польза в сохранении как абстрактного класса, так и интерфейса?

Спасибо!

Это было полезно?

Решение

Определенно.Давайте подумаем о конкретном примере.

Допустим, у нас есть абстрактный класс Animal.Скажем, мы создаем несколько подклассов Cat, Dog, Mosquito, и Eagle.Мы можем реализовать его Eat(), Breathe(), Sleep() методы абстрактного класса Animal.

Пока все так хорошо.Теперь, допустим, мы хотим иметь Fly() способ для Mosquito и Eagle классы.Поскольку эти два организма на самом деле не очень хорошо связаны (один - птица, другой - насекомое), было бы нелегко найти общего предка для них двоих, которого мы могли бы иметь в виде абстрактного класса.Лучше всего это было бы реализовано с помощью интерфейса IFly.

В IFly интерфейс может иметь Fly() метод, который должен быть реализован.И то, и другое Mosquito и Eagle оба класса могут быть подклассами абстрактного класса Animal и реализовать интерфейс IFly и уметь Eat(), Breathe(), Sleep() и Fly() без наличия какого-либо странного родственного отношения между двумя классами.

Другие советы

Обычно я программирую для абстрактных классов, когда это имеет смысл, и реализую (и создаю во внешней сборке / библиотеке контрактов) интерфейс в каждом классе (абстрактном или нет), чтобы мне было легче реализовать Windows Communication Foundation или инверсия управления когда это необходимо (что почти всегда делается для издевательства).Это стало для меня второй натурой.

Абсолютно.Интерфейс - это всегда правильный путь - таким образом, его может реализовать что угодно (включая то, у чего уже есть родительский элемент).

Абстрактный класс, как правило, делает это так, что вам не нужно переопределять некоторые части этой функциональности.Swing использует это немного, у них будет интерфейс, а затем реализация по умолчанию, чтобы вы могли переопределить только один из 5 методов, или это может позаботиться о добавлении слушателей для вас, но вам не обязательно использовать этот базовый класс, если вы этого не хотите.

Если ваш абстрактный класс является Только класс, который когда-либо будет реализовывать интерфейс, тогда вы всегда можете просто проверить наличие экземпляров абстрактного класса, вам не нужен интерфейс.Но если вы хотите быть совместимыми в будущем с новыми, еще не написанными классами, которые не будут расширять абстрактный класс, но могли бы использовать интерфейс, то продолжайте использовать интерфейс сейчас.

Я согласен с cfeduke.Я ВСЕГДА начинаю с интерфейсов и в прошлом использовал абстрактные классы, которые реализуют интерфейсы и предоставляют базовую функциональность для содействия повторному использованию кода среди классов, наследуемых от абстрактного класса.Mocking и IOC, вообще говоря, зависят от интерфейса, только по этой причине я бы использовал интерфейсы в своих проектах.

Если абстрактный класс обладает функциональностью, разумно сохранить его.Но если он содержит только абстрактные методы и никаких полей.Я не вижу смысла сохранять и то, и другое.

Редактировать: Я работаю над устаревшим кодом с большим количеством абстрактных классов.Если у меня когда-нибудь будет время, я добавлю интерфейсы (и, возможно, удалю пустые аннотации).Потому что работа с интерфейсами значительно расширяет возможности.И они чтят свое имя, точно определяя интерфейс.

Ваш интерфейс определяет контракт, который должен быть выполнен для принятия объекта;ваш абстрактный класс определяет контракт, который должен быть выполнен, И определяет некоторые конкретные детали реализации.

Подумайте об этом с такой точки зрения;если вы думаете, что когда-либо возможно, чтобы кто-то захотел выполнить этот контракт иным способом, чем тот, который набрасывает абстрактный класс (скажем, с другой реализацией резервного типа данных), то у вас должны быть как интерфейс, так и абстрактный класс, который это реализует.

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

Я бы всегда советовал вам использовать интерфейсы.Абстрактные классы имеют то преимущество, что вы можете добавить функциональность по умолчанию, но требовать, чтобы пользователь использовал их единственное наследование, довольно агрессивно.

Библиотеки классов Microsoft в ряде случаев предпочитают абстрактные классы интерфейсам, поскольку это позволяет им изменять базовый класс.Добавление метода в абстрактный класс редко приводит к нарушению того, кто наследует от него.Добавление метода в интерфейс всегда нарушает работу его разработчиков.Однако это обеспечивает одну из лучших причин для использования интерфейсов:ужасная вероятность того, что Microsoft, возможно, уже использовала ваше единственное наследство.

Однако я бы предположил, что в вашем конкретном случае вы, возможно, захотите вернуться к используемому вами шаблону проектирования.Кажется необычным иметь много классов "logon-type".

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

Вы могли бы расширить функциональность подклассов, создав новый интерфейс с другим набором методов.

Предполагая , что вы спрашиваете конкретно , когда интерфейс и абстрактный класс имеют идентичные сигнатуры ...

...(Если члены интерфейса каким-либо образом отличаются от членов абстрактного класса, то, конечно, ответ - да, может потребоваться и то, и другое)

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top