Есть ли польза от наличия абстрактного класса и интерфейса?

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

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

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

Спасибо!

10 ответов

Решение

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

Скажем, у нас есть абстрактный класс 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, возможно, уже использовала ваше одно наследство.

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

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

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

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

Другие вопросы по тегам