Как выглядит полиморфизм с использованием интерфейсов?

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

Спасибо


person JavaSa    schedule 06.08.2012    source источник
comment
возможный дубликат совместимы ли интерфейсы с полиморфизмом   -  person dash    schedule 07.08.2012


Ответы (3)


Как заявил Андреас Хартл в своей статье о наследовании и наследовании. Интерфейсы:

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

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

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

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

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

Но что использовать, если вы свободны в выборе? По сути, базовые классы описывают и реализуют общее поведение связанных типов, а интерфейсы описывают функциональность, которую могут реализовать несвязанные типы. Наследование описывает отношения «есть», интерфейсы описывают отношения «похоже». Например, скажем, вы пишете авиасимулятор. Ваш основной объект, который вы, например, сохраните в списке, будет «Самолет». Вашими конкретными типами будут «Конкорд» и «Фантом». Итак, как вы должны моделировать эти три типа? Concorde и Phantom связаны между собой, они оба являются самолетами и имеют общие данные, такие как «Вес» или «Макс. скорость», и функции, такие как «Ускорение», поэтому мы можем моделировать их с помощью наследования. «Самолет» будет базовым классом с общими данными и методами, а «Конкорд» и «Фантом» будут производными от «Самолета». Мы могли бы сказать, что оба являются специализированными самолетами, поэтому часто говорят, что наследование означает специализацию. Теперь предположим, что мы также добавляем в нашу программу класс «Пилот» и хотим дать пользователю возможность сохранять игру и загружать ее позже. Поэтому, когда он сохраняет игру, нам нужно сохранить состояние всех Самолетов и состояние всех Пилотов. И мы хотим сделать это в одной функции, которая принимает только список всех сохраняемых объектов. Итак, как мы моделируем это? Чтобы ответить на этот вопрос, мы должны взглянуть на различные типы, которые мы хотим сохранить. Пилоты и самолеты. Совершенно очевидно, что они никак не связаны. У них нет общих данных и общих функций. Мы видим, что написание базового класса «Saveable» и получение от него как Pilot, так и Airplane не имеет большого смысла, поскольку код в Saveable не может быть повторно использован Airplane или Pilot, поскольку оба не имеют общих свойств. В этом случае интерфейс — лучшее решение. Мы можем написать интерфейс «ISaveable» с помощью метода Save(). Затем Pilot может реализовать ISaveable.Save(), сохранив свое имя, в то время как Airplane может сохранить свою текущую скорость и координаты.

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

Вот еще несколько моментов, которые следует учитывать при наследовании и интерфейсах:

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

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

  • Интерфейсы помогают защитить внутренние классы. Предположим, что класс A имеет внутренний объект b класса B. Когда метод в A возвращает указатель или ссылку на b, код, вызвавший этот метод, теперь имеет доступ ко всему объекту b, который может быть опасно, если A хочет разоблачить только определенных членов b. Эта проблема может быть решена, если вы создадите интерфейс только с теми элементами, которые можно безопасно выставлять напоказ. Когда B реализует этот интерфейс, а ваш метод в A возвращает b через указатель или ссылку I, внешний код может делать только то, что вы разрешаете через интерфейс.

person Jakub Konecki    schedule 06.08.2012
comment
Чувак, ты все это за 4 минуты напечатал? ;-) - person lesscode; 07.08.2012
comment
и здесь начинают действовать шаблоны проектирования. Они помогают вам принимать эти решения. - person DarthVader; 07.08.2012
comment
-1 - Я думал, вы напечатали это за 4 минуты только для того, чтобы узнать, что это копипаста, не отдав должного внимания ссылке, кроме расплывчатой ​​ссылки в конце. Вам будет стыдно за день! - person Metro Smurf; 07.08.2012
comment
Это копия ссылки в конце текста, которая не ослабляет ответ; на самом деле, приятно видеть что-то, что не является просто ответом только на ссылку, чтобы со временем неизбежно избежать ужасной ошибки 404. Тем не менее, я бы четко указал оригинального автора - в конце концов, они сделали свою работу. - person dash; 07.08.2012
comment
@dash: я не минусовал, но имхо приятно видеть столько текста без комментария или выделения. Это тонуть или плавать - person Tim Schmelter; 07.08.2012
comment
@TimSchmelter Полностью согласен с тем, что это можно перефразировать, но один или два раза меня поймали на ответах только по ссылкам, которые ведут к контенту, которого больше не существует, но я не проголосовал, потому что слишком много текста без кредита. Важно найти правильный баланс. Говоря, что... stackoverflow.com/questions/6147658/ - person dash; 07.08.2012
comment
Простое размещение ссылки в конце недостаточно указывает на то, что весь ответ, который вы здесь дали, был процитирован из этого источника. Я отредактировал ответ, чтобы лучше цитировать исходную статью. - person Brad Larson; 10.08.2012

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

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

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

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

Когда дело доходит до C#, просто знайте, что интерфейс указывает, какие свойства или члены объекта, который его реализует, ДОЛЖЕН иметь. Аналогично, в C# большое отличие состоит в том, что вы можете наследовать несколько интерфейсов, но только один класс. (т.е. public class Test : BaseClass, IDisposable, ITest, IFooBar)

person Erik Funkenbusch    schedule 06.08.2012

учти это...

public int SomeMethod(SomeBaseClass object)
{
  // Pass in a descendant classe that implements / overrides some method in SomebaseClass
}

public int SomeMethod(ISomeInterface intf)
{
   // pass in concrete classes that implement some ISomeInterface function 
}

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

person Tim Jarvis    schedule 06.08.2012
comment
другой парень написал 2 страницы, и ты соревнуешься с ним. с привет мир? - person DarthVader; 07.08.2012
comment
@DarthVader - скопировал/вставил другой парень. - person Metro Smurf; 07.08.2012
comment
2 страницы только усложняют довольно простую концепцию. - person Tim Jarvis; 07.08.2012