Есть ли польза от наличия абстрактного класса и интерфейса? - PullRequest
11 голосов
/ 06 ноября 2008

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

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

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

Спасибо!

Ответы [ 10 ]

15 голосов
/ 06 ноября 2008

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

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

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

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

4 голосов
/ 06 ноября 2008

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

2 голосов
/ 06 ноября 2008

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

2 голосов
/ 06 ноября 2008

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

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

1 голос
/ 06 ноября 2008

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

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

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

1 голос
/ 06 ноября 2008

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

1 голос
/ 06 ноября 2008

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

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

0 голосов
/ 06 ноября 2008

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

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

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

0 голосов
/ 06 ноября 2008

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

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

0 голосов
/ 06 ноября 2008

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

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

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

...