Есть ли разница между интерфейсами и абстрактными классами, которые имеют только абстрактные методы?

9

Допустим, у нас есть абстрактный класс, и пусть этот класс имеет только абстрактные методы. Отличается ли этот абстрактный класс от интерфейса, который имеет только те же методы?

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

yfklon
источник
на каком языке?
Кевин Клайн
Насколько я могу судить, на ваш вопрос в двух экземплярах ответили дважды : здесь и здесь . И эти два ответа не зависят от языка, ничего особенного для C # нет
gnat
3
@blank Я не согласен со статусом Duplicate, примененным к вашему вопросу, поэтому снова открыл его. Далее я отредактировал ваш вопрос, чтобы уточнить, что, по вашему мнению, вы спрашиваете.
maple_shaft

Ответы:

22

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

Абстрактный суперкласс - это именно то, на что он похож, это общий тип, который разделяют многие другие типы, например, Кошки и Собаки - Животные.

Интерфейс - это также то, на что он похож, это интерфейс, через который другие классы могут взаимодействовать с объектом. Если вы хотите сделать Cat Walk, вы в порядке, потому что Cat реализует интерфейс CanWalk. То же самое для Ящерицы, хотя они ходят совсем по-другому. Снейк, с другой стороны, не реализует CanWalk, поэтому вы не можете передать его Walk. Между тем, Lizard и Snake (или, возможно, более явные подклассы - я не эксперт) могли бы сбросить свой скин и, таким образом, реализовать CanShed, в то время как Cat не мог этого сделать.

Но они все еще животные и имеют некоторые общие свойства, например, живы они или мертвы.

Вот почему все методы интерфейса должны быть реализованы как общедоступные (или явно в C #). Потому что какой смысл в интерфейсе, который скрыт от класса, взаимодействующего с объектом? Именно поэтому вы можете иметь несколько интерфейсов для объекта, даже если язык не поддерживает множественное наследование.

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

прецизионный самописец
источник
4
+1, хотя кошки сбрасывают гораздо более раздражающий способ, чем змеи или ящерицы.
Мэтью Флинн
Технически: абстрактные методы могут быть защищены. Методы интерфейса не могу.
Жак Коортс
19

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

herzmeister
источник
3
наиболее? какие из них вы считаете? Большинство известных мне ООП-языков не имеют интерфейсов или абстрактных классов. C ++ имеет только абстрактные классы.
Кевин Клайн
10
@kevincline: вероятно, C #, Java и VB.NET.
tdammers
1
@kevincline, я думаю, что просто не хватает «обоих». IIRC, в Аде мотивация для интерфейса заключалась в том, что разработчики не хотели использовать общую функцию множественного наследования, но особый случай интерфейса был сочтен слишком важным, чтобы его не предоставлять.
AProgrammer
@tdammers: LOL. Это была шутка, верно?
Кевин Клайн
3

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

В таких языках, как PHP и C #, интерфейсы предоставляют средства для достижения аналогичного полиморфизма, хотя мне не нравится называть это «наследованием», поскольку существует концептуальная разница между наследованием абстрактного класса и реализацией интерфейса. Интерфейсы устраняют проблему конфликта, потому что они сами не обеспечивают реализацию.

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

Основное концептуальное отличие состоит в том, что когда класс наследует другой класс (абстрактный или нет), возникает отношение «есть», поэтому «а» Carесть «а» Vehicleи « Dogесть» Animal. С интерфейсом важно то, что делает объект. Таким образом, Carи Dogможет, Move()и потребитель знает это, потому что они реализуют Movable, но Автомобиль определенно не Dog, или Animal. И реализация перемещения будет отличаться (колеса против ног), но код потребления не заботится и не должен волноваться. Интерфейсы все о потреблении кода, а не о реализации.

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

Иван Пинтар
источник
Интерфейс также является типом, так что вы можете иметь IAnimal, который Dogи Cat есть, и есть .
Эми Бланкеншип
Вы могли бы, но, на мой взгляд, интерфейсы связаны с поведением, которое подвергается воздействию внешнего мира, а не с тем, что представляют собой объекты. Наследование подразумевает, что что-то является типом чего-то другого (Кошка - Животное). Интерфейс просто говорит, что может сделать этот объект. Вот почему я хотел бы сказать, что что-то «реализует», а не «наследует» от интерфейса, что скажет большинство .Net людей, с которыми я работал (я думаю, потому что синтаксис одинаков для наследования и реализации).
Иван Пинтар
2

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

Править Сначала я думал, что закрытый абстрактный метод бесполезен, но теперь я вспомнил, что его можно использовать, чтобы этот метод никогда не вызывался. Таким образом, вы можете предотвратить вызов конструктора копирования объекта.

Томас
источник
1
Защищенные виртуальные (переопределяемые) методы могут быть полезны для классов, являющихся частью инфраструктуры или чего-то подобного. Таким образом они гарантируют, что пользовательский код в классе, который наследует реферат, обеспечивает эту функциональность. Хотя этого также можно достичь, унаследовав интерфейс базового класса, но фактически не реализовав его методы
Иван Пинтар,
Да, я думал о чем-то подобном, но не имел никакого опыта с этим, поэтому не мог судить. Спасибо за вклад.
Томас
Просто записка. В некоторых языках частные виртуальные методы могут быть переопределены в производных классах.
Йохан Буле
2

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

Кевин Клайн
источник
2

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

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

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

tgkprog
источник
1
Разве абстрактные методы не определены без какой-либо реализации и оставляют реализацию наследующим классам?
Иван Пинтар
да, вы правы, тогда я думаю, это просто переменные, конструкторы и статические и приватные методы, если вы посчитаете их
tgkprog
@Pinetree, на практике большую часть времени вам понадобится хотя бы немного «реального» кода в ваших абстрактных классах (по крайней мере, на языке, который я использую, который не имеет специальной конструкции для абстрактных классов).
Эми Бланкеншип
@AmyBlankenship: да, в большинстве случаев абстрактные классы действительно имеют «реальный» код (для этого они и существуют). Но я имел в виду абстрактные методы в контексте чисто абстрактного класса, который служит интерфейсом в языке, подобном C ++, который не имеет интерфейсов.
Иван Пинтар