Подтвердить что ты не робот

Есть ли смысл иметь как абстрактный класс, так и интерфейс?

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

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

Есть ли смысл поддерживать как абстрактный класс, так и интерфейс?

Спасибо!

4b9b3361

Ответ 1

Конечно. Подумайте о конкретном примере.

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

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

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

Ответ 2

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

Ответ 3

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

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

Ответ 4

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

Ответ 5

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

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

Ответ 6

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

Ответ 7

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

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

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

Ответ 8

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

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

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

Ответ 9

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

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

Ответ 10

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

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

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