Зачем использовать интерфейсы, множественное наследование и интерфейсы, преимущества интерфейсов? - PullRequest
61 голосов
/ 16 декабря 2011

У меня все еще есть некоторая путаница по поводу этой вещи.До сих пор я находил

(Подобные вопросы уже задавались здесь, но у меня были другие вопросы.)

  1. Интерфейс - это коллекция ТОЛЬКОабстрактные методы и конечные поля.

  2. В Java нет множественного наследования.

  3. Для достижения множественного наследования в Java можно использовать интерфейсы.

  4. Одним из сильных сторон наследования является то, что мы можем использовать код базового класса в производном классе, не записывая его снова.Может быть, это самое важное для наследства.

Сейчас ..

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

Q2.Если реализация интерфейса не является наследованием, то как интерфейсы используются для достижения множественного наследования?

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

Тогда зачем создавать интерфейсы?

ПРИМЕЧАНИЕ: Я нашел один случай, когда интерфейсы полезны.Одним из примеров этого является то, что в интерфейсе Runnable у нас есть публичный метод void run (), в котором мы определяем функциональность потока, и существует встроенное кодирование, согласно которому этот метод будет запускаться как отдельный поток.Так что нам просто нужно написать код, что делать в потоке, Rest предопределен.Но и этого можно добиться с помощью абстрактных классов и всего остального.

Тогда каковы точные преимущества использования интерфейсов?Это действительно множественное наследование, которое мы достигаем с помощью интерфейсов?

Ответы [ 12 ]

35 голосов
/ 16 декабря 2011

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

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

Q2.Если реализация интерфейса не является наследованием, то как интерфейсы используются для достижения множественного наследования?

Это не так.С интерфейсами один класс может иметь несколько « представлений », различные API или возможности.Например, класс может быть Runnable и Callable одновременно, в то время как оба метода фактически выполняют одно и то же.

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

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

Существует несколько сценариев использования интерфейсов:

  1. Объект фактически имеет две идентичности: a Tank равен и Vehicle и Weapon.Вы можете использовать экземпляр Tank, где ожидается либо первое, либо второе (полиморфизм).Это редко встречается в реальной жизни и является действительным примером, когда множественное наследование было бы лучше (или черты).

  2. Простые обязанности: экземпляр объекта Tank вигра также Runnable позволяет вам выполнять ее в потоке и ActionListener реагировать на события мыши.

  3. Интерфейсы обратного вызова: если объект реализует данный интерфейс обратного вызова, онуведомление о его жизненном цикле или других событиях.

  4. Маркерные интерфейсы: не добавляются никакие методы, но легко доступны через instanceof для обнаружения возможностей или желаний объекта.Serializable и Cloneable являются примерами этого.

Вам нужны черты (как в Scala), к сожалению, недоступные в Java.

20 голосов
/ 25 января 2012

Интерфейсы - это набор конечных статических полей и абстрактных методов (недавно в Java 8 добавлена ​​поддержка наличия статических методов в интерфейсе).

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

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

interface Animal {
    public void eat();
    public void sleep();   
}

class Lion implements Animal {
    public void eat() {
        // Lion's way to eat
    }

    public void sleep(){
         // Lion's way to sleep
    }
}

class Monkey implements Animal {
    public void eat() {
        // Monkey's way to eat
    }

    public void sleep() {
        // Monkey's way to sleep
    }
}

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

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

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

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

Q2. Если реализация интерфейса не является наследованием, то как интерфейсы используются для достижения множественного наследования?

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

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

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

Подробнее читайте в моей книге здесь и здесь

9 голосов
/ 20 ноября 2012

KISS

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

Я предпочитаю Keep It Simple Stupid, поэтому предложу мой новый найденный вид интерфейсов.

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

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

Пояснение

Три кнопки в форме, при нажатии на каждую из которых сохраняется ссылка на другой класс,переменная интерфейса (_data).Весь смысл различных ссылок на классы в переменную интерфейса, это то, что я не понял, так как она казалась избыточной, тогда ее мощность становится очевидной с помощью msgbox, мне нужно только вызвать тот же метод, чтобы выполнить задачу, в которой я нуждаюсь, в этомcase 'GetData ()', который использует метод в классе, который в настоящее время хранится в справочной переменной интерфейса (_data).

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

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

Когда использовать

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

Я искренне надеюсь, что это поможет товарищу Noob с этим сложным принципом.

Public Class Form1

Private _data As IData = Nothing

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    _data = New DataText()
    MsgBox(_data.GetData())
End Sub

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
    _data = New DataDB()
    MsgBox(_data.GetData())
End Sub

Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
    _data = New DataWeb()
    MsgBox(_data.GetData())
End Sub

End Class

Public Interface IData
Function GetData() As String
End Interface

Friend Class DataText : Implements IData

Friend Function GetData() As String Implements IData.GetData
    Return "DataText"
End Function

End Class

Friend Class DataDB : Implements IData

Friend Function GetData() As String Implements IData.GetData
    Return "DataDB"
End Function

End Class

Friend Class DataWeb : Implements IData

Friend Function GetData() As String Implements IData.GetData
    Return "DataWeb"
End Function

End Class
5 голосов
/ 13 марта 2016

Это очень старый вопрос, и в выпуске java-8 добавлены дополнительные функции и возможности интерфейса.

Объявление интерфейса может содержать

  1. сигнатуры метода
  2. методы по умолчанию
  3. статические методы
  4. определения констант.

Единственными методами, которые имеют реализации в интерфейсе, являются стандартные и статические методы.

Использование интерфейса:

  1. Чтобы определить контракт
  2. Чтобы связать несвязанные классы с возможностями (например, классы, реализующиеСериализуемый интерфейс может иметь или не иметь какую-либо связь между ними, кроме реализации этого интерфейса
  3. Для обеспечения взаимозаменяемой реализации, например Strategy_pattern
  4. методы по умолчанию позволяют добавлять новые функциональные возможности к интерфейсам ваших библиотек и обеспечивать двоичную совместимость с кодом, написанным для более старых версий этих интерфейсов
  5. Организация вспомогательных методов в ваших библиотеках с помощью static методы (вы можете хранить статические методы, специфичные для интерфейса в том же интерфейсе, а не в отдельном классе)

Посмотрите на этот связанный вопрос SE для foПример кода для лучшего понимания концепций:

Как мне объяснить разницу между интерфейсом и абстрактным классом?

Возвращаясь к вашим запросам:

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

Q2.Если реализация интерфейса не является наследованием, то как интерфейсы используются для достижения множественного наследования?

Интерфейс может содержать код для методов static и default .Эти методы по умолчанию обеспечивают обратную совместимость, а статические методы предоставляют функции helper / utility .

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

Вы можете заменить наследование с возможностью . Интерфейс предоставляет множество возможностей для реализации классов.

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

См. Раздел " использования интерфейса " в моем ответе.

5 голосов
/ 16 декабря 2011

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

К сожалению, в разговорной речи слово inheritance все еще часто используется, когда класс реализует интерфейс, хотя interface implementation будет предпочтительным термином - IMO,термин inheritance должен строго использоваться с наследованием конкретного или абстрактного класса.В таких языках, как C ++ и C #, один и тот же синтаксис (т. Е. Subclass : Superclass и Class : Interface) используется как для наследования классов, так и для реализации интерфейса, что, возможно, способствовало распространению неправильного использования слова inheritance с интерфейсами.Java имеет другой синтаксис для extend класса, в отличие от implement интерфейса, что хорошо.

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

Вы можете добиться «эффекта» множественного наследования с помощью композиции - реализовав несколько интерфейсов в классе, а затем предоставив реализации для всех методов, свойств и событий, требуемых для всех интерфейсовна уроке.Один из распространенных способов сделать это с конкретными классами - это создать отношения has-a (композиция) с классами, которые реализуют внешние интерфейсы, «связывая» реализацию с каждой из реализаций внутреннего класса.(Такие языки, как C ++, напрямую поддерживают множественное конкретное наследование, но это создает другие потенциальные проблемы, такие как проблема с бриллиантами).

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

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

Пример реального мира

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

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

Зачем использовать интерфейсы?

Интерфейсы отлично подходят для слабой связи классов иодна из опор SOLID парадигмы дяди Боба, особенно Dependency Inversion Principle и Interface Segregation Principles.

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

В тестировании заглушки и макеты зависимостей могут использоваться для модульного тестирования каждого класса,и взаимодействие, которое класс имеет с зависимостью, можно «шпионить» за

3 голосов
/ 16 декабря 2011

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

Полиморфизм - это когда у вас есть код, который использует интерфейс, а его экземплярный объект может иметь любой класс, производный от этого интерфейса. Например, у меня может быть такой метод: public void Pet (IAnimal animal) и этот метод получит объект, который является экземпляром Dog или Cat, который наследуется от IAnimal. или я могу иметь такой код: Животное животное и тогда я могу вызвать метод этого интерфейса: animal.Eat (), который Dog или Cat может реализовать по-другому.

Основным преимуществом интерфейсов является то, что вы можете наследовать от некоторых из них, но если вам нужно наследовать только от одного, вы также можете использовать абстрактный класс. Вот статья, которая объясняет больше различий между абстрактным классом и интерфейсом: http://www.codeproject.com/KB/cs/abstractsvsinterfaces.aspx

2 голосов
/ 06 апреля 2018

Старый вопрос.Я удивлен, что никто не процитировал канонические источники: Java: обзор Джеймса Гослинга, Шаблоны проектирования: элементы многоразового объектно-ориентированного программного обеспечения Бандой четырех или Эффективная Java Джошуа Блоха (среди других источников).

Я начну с цитаты:

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

Теперь давайте по очереди рассмотрим ваши предположения и вопросы (я добровольно проигнорирую возможности Java 8).

Предположения

Интерфейс - это коллекция ТОЛЬКО абстрактных методов и конечных полей.

Вы видели ключевое слово abstract в интерфейсах Java?Нет. Тогда вы не должны рассматривать интерфейс как набор абстрактных методов.Возможно, вас вводят в заблуждение так называемые интерфейсы C ++, которые являются классами только с чисто виртуальными методами.C ++ по своему дизайну не имеет (и не должен иметь) интерфейсов, потому что он имеет множественное наследование.

Как объяснил Гослинг, вы должны скорее рассматривать интерфейс как "набор методов, которые объектотвечает на ".Мне нравится видеть интерфейс и соответствующую документацию в качестве сервисного контракта.Он описывает, что вы можете ожидать от объекта, который реализует этот интерфейс.В документации должны быть указаны предварительные и последующие условия (например, параметры должны быть не нулевыми, выходные данные всегда положительными, ...) и инварианты (метод, который не изменяет внутреннее состояние объекта).Этот контракт является сердцем, я думаю, ООП.

В Java нет множественного наследования.

Действительно.

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

Ничего добавить.

Интерфейсы могут использоваться для достижения множественного наследования в Java.

Нет, simlpy, потому что нетмножественное наследование в Java.См. Выше.

Одна сильная сторона наследования заключается в том, что мы можем использовать код базового класса в производном классе, не записывая его снова.Может быть, это самое важное для наследования.

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

Но у него есть важный аналог:

родительские классы часто определяют хотя бы часть физического представления своих подклассов.Поскольку наследование предоставляет подклассу детали реализации его родителя, часто говорят, что «наследование нарушает инкапсуляцию» [Sny86].Реализация подкласса становится настолько связанной с реализацией его родительского класса, что любое изменение в реализации родителя заставит подкласс измениться.(GOF, 1.6)

(в Блохе есть аналогичная цитата, пункт 16).

На самом деле наследование служит и другой цели:

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

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

Вопросы

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

Реализация интерфейса не наследование. Это реализация. Таким образом, ключевое слово implements.

Q2. Если реализация интерфейса не является наследованием, то как интерфейсы используются для достижения множественного наследования? **

Нет множественного наследования в Java. Смотри выше.

Q3. В любом случае, какова польза от использования интерфейсов? У них нет никакого кода. Нам нужно снова и снова писать код во всех классах, которые мы его реализуем. / Тогда зачем создавать интерфейсы? / Каковы точные преимущества использования интерфейсов? Действительно ли мы получаем множественное наследование с помощью интерфейсов?

Самый важный вопрос: почему вы хотите иметь множественное наследование? Я могу придумать два ответа: 1. дать типы множественных объектов объекту; 2. повторно использовать код.

Присвоение объектам типов Mutliple

В ООП один объект может иметь разных типов . Например, в Java ArrayList<E> имеет следующие типы: Serializable, Cloneable, Iterable<E>, Collection<E>, List<E>, RandomAccess, AbstractList<E>, AbstractCollection<E> и Object ( Надеюсь я никого не забыл). Если объект имеет разные типы, различные потребители смогут использовать его, не зная о его особенностях. Мне нужен Iterable<E>, а вы даете мне ArrayList<E>? Все нормально. Но если мне нужен List<E>, а вы даете мне ArrayList<E>, это тоже нормально. И т.д.

Как вы вводите объект в ООП? В качестве примера вы взяли интерфейс Runnable, и этот пример идеально подходит для иллюстрации ответа на этот вопрос. Я цитирую официальный документ Java:

Кроме того, Runnable предоставляет средства для того, чтобы класс был активным, не наследуя Thread.

Вот в чем смысл: Наследование - это удобный способ ввода объектов. Вы хотите создать поток? Давайте создадим подкласс класса Thread. Вы хотите, чтобы объект имел разные типы, давайте используем mutliple-наследование. Argh. Это не существует в Java. (В C ++, если вы хотите, чтобы объект имел разные типы, множественное наследование - это путь.)

Как тогда придавать объектам типы mutliple? В Java вы можете напечатать свой объект напрямую . Это то, что вы делаете, когда ваш класс implements интерфейс Runnable. Зачем использовать Runnable, если вы поклонник наследства? Возможно, потому что ваш класс уже является подклассом другого класса, скажем, A. Теперь у вашего класса есть два типа: A и Runnable.

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

Повторное использование кода

Это сложный предмет; Я уже процитировал GOF о нарушении инкапсуляции. Другой ответ затронул проблему алмазов. Можно также подумать о принципе единой ответственности:

У класса должна быть только одна причина для изменения. (Роберт К. Мартин, Agile Software Development, принципы, шаблоны и практики)

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

Реализация суперкласса может меняться от релиза к релизу, и, если это так, подкласс может сломаться, даже если его код не был затронут. Как следствие, подкласс должен развиваться в тандеме со своим суперклассом (Блох, пункт 16).

Я бы добавил более прозаическую проблему: у меня всегда возникает странное чувство, когда я пытаюсь найти исходный код метода в классе, но не могу его найти. Тогда я помню: это должно быть определено где-то в родительском классе. Или в классе бабушек и дедушек. Или, может быть, даже выше. Хорошая IDE в этом случае является ценным активом, но, на мой взгляд, остается чем-то волшебным. Ничего похожего с иерархиями интерфейсов, так как мне нужен только javadoc: один ярлык клавиатуры в IDE, и я его получаю.

У наследства есть преимущества:

Безопасно использовать наследование в пакете, где реализации подкласса и суперкласса находятся под контролем одних и тех же программистов. Также безопасно использовать наследование при расширении классов, специально разработанных и задокументированных для расширения (пункт 17: Разработка и документация для наследования или иное запрещение). (Блох, п.16)

Примером класса, "специально разработанного и задокументированного для расширения" в Java, является AbstractList.

Но Блох и GOF настаивают на этом: «Пользуйся композицией по наследству»:

Делегирование - это способ сделать композицию такой же мощной для повторного использования, как наследование [Lie86, JZ91]. При делегировании два объекта участвуют в обработке запроса: принимающий объект делегирует операции своему делегату. Это аналогично подклассам, откладывающим запросы к родительским классам. (GOF стр.32)

Если вы используете композицию, вам не придется писать один и тот же код снова и снова. Вы просто создаете класс, который обрабатывает дубликаты, и передаете экземпляр этого класса классам, которые реализует интерфейс. Это очень простой способ повторного использования кода. И это поможет вам следовать принципу единой ответственности и сделать код более тестируемым. У Rust и Go нет наследования (у них тоже нет классов), но я не думаю, что код более избыточен, чем в других языках ООП.

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

Примечание: вы можете поделиться кодом с интерфейсами Java 8

И, наконец, последняя цитата:

Во время незабываемой сессии вопросов и ответов кто-то спросил его [Джеймса Гослинга]: «Если бы вы могли снова заняться Java, что бы вы изменили?» «Я бы пропустил занятия» (где-нибудь в сети, не знаю, правда ли это)

2 голосов
/ 03 апреля 2018

Оба метода работают (интерфейсы и множественное наследование).

Быстрый практический короткий ответ

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

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

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

Не торопитесь использовать интерфейсы.

Длинный скучный ответ

Интерфейсы оченьпохожи или даже эквивалентны абстрактным классам.

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

Следующий код с абстрактными классами:


MyStreamsClasses.java

/* File name : MyStreamsClasses.java */
import java.lang.*;
// Any number of import statements

public abstract class InputStream {
  public void ReadObject(Object MyObject);
}

public abstract class OutputStream {
  public void WriteObject(Object MyObject);
}

public abstract class InputOutputStream 
    imnplements InputStream, OutputStream {
  public void DoSomethingElse();
}

Может быть заменено на:


MyStreamsInterfaces.java

/* File name : MyStreamsInterfaces.java */
import java.lang.*;
// Any number of import statements

public interface InputStream {
  public void ReadObject(Object MyObject);
}

public interface OutputStream {
  public void WriteObject(Object MyObject);
}

public interface InputOutputStream 
    extends InputStream, OutputStream {
  public void DoSomethingElse();
}

Приветствия.

0 голосов
/ 22 мая 2019

Итак.Здесь есть много отличных ответов, подробно объясняющих, что такое интерфейс.Тем не менее, это пример его использования, как один из моих лучших коллег когда-либо объяснил мне это много лет назад, с тем, что я усвоил в университете за последние пару лет.

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

«Код дополнением, а не модификацией» - МагнусМэдсен, AAU

Это то, что он назвал по крайней мере, и он может иметь его из какого-то другого места. Пример кода ниже написан на C #, но все показанное можно сделать примерно так жена Яве.

То, что мы видим, это класс с именем SampleApp, который имеет одно поле, IOContext.IOContext - это интерфейс.SampleApp не заботится о том, как он сохраняет свои данные, он просто нуждается в этом в методе doSomething ().

Мы можем представить, что в начале процесса разработки сохраняются данныевозможно, было важнее, чем то, КАК это было сохранено, и поэтому разработчик решил просто написать класс FileContext.Позже, однако, ему нужно было поддерживать JSON по любой причине.Поэтому он написал класс JSONFileContext, который наследует FileContext.Это означает, что это фактически IOContext, который имеет функциональность FileContext, сохраняет замену FileContexts SaveData и LoadData, он все еще использует свои методы «запись / чтение».

Реализация класса JSON была небольшойобъем работы, по сравнению с написанием класса и его наследованием IOContext.

Поле SampleApp могло бы иметь тип FileContext, но в этом случае оно было бы ограничено толькоиспользуя детей этого класса.Создавая интерфейс, мы можем даже реализовать реализацию SQLiteContext и записать в базу данных, SampleApp никогда не узнает и не позаботится, и когда мы напишем класс sql lite, нам нужно будет сделать только одно изменение в нашем коде: new JSONFileContext();становится new SQLiteContext();

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

так: код добавляется, а НЕ изменяется.

namespace Sample
{
    class SampleApp
    {
        private IOContext context;

        public SampleApp()
        {
            this.context = new JSONFileContext(); //or any of the other implementations
        }

        public void doSomething()
        {
            //This app can now use the context, completely agnostic of the actual implementation details.
            object data = context.LoadData();
            //manipulate data
            context.SaveData(data);
        }
    }

    interface IOContext
    {
        void SaveData(object data);
        object LoadData();
    }

    class FileContext : IOContext
    {
        public object LoadData()
        {

            object data = null;
            var fileContents = loadFileContents();
            //Logic to turn fileContents into a data object
            return data;
        }

        public void SaveData(object data)
        {
            //logic to create filecontents from 'data'
            writeFileContents(string.Empty);
        }

        protected void writeFileContents(string fileContents)
        {
            //writes the fileContents to disk
        }

        protected string loadFileContents()
        {
            string fileContents = string.Empty;
            //loads the fileContents and returns it as a string
            return fileContents;
        }
    }

    class JSONFileContext : FileContext
    {
        public new void SaveData(object data)
        {
            //logic to create filecontents from 'data'
            base.writeFileContents(string.Empty);
        }

        public new object LoadData()
        {
            object data = null;
            var fileContents = loadFileContents();
            //Logic to turn fileContents into a data object
            return data;
        }
    }

    class SQLiteContext : IOContext
    {
        public object LoadData()
        {
            object data = null;
            //logic to read data into the data object
            return data;
        }

        public void SaveData(object data)
        {
            //logic to save the data object in the database
        }
    }
}
0 голосов
/ 03 апреля 2018

Q1. Поскольку интерфейсы имеют только абстрактные методы (без кода), как мы можем сказать, что если мы реализуем интерфейс, то это наследование? Мы не используем его код.

Это не равное наследство. Это просто похоже. Позвольте мне объяснить:

VolvoV3 extends VolvoV2, and VolvoV2 extends    Volvo (Class)
VolvoV3 extends VolvoV2, and VolvoV2 implements Volvo (Interface)

line1: Volvo v = new VolvoV2(); 
line2: Volvo v = new VolvoV3(); 

Если вы видите только строки 1 и 2, вы можете сделать вывод, что VolvoV2 и VolvoV3 имеют одинаковый тип. Вы не можете определить, является ли Volvo суперклассом или Volvo интерфейсом.

Q2. Если реализация интерфейса не является наследованием, то как интерфейсы используются для достижения множественного наследования?

Теперь с использованием интерфейсов:

VolvoXC90 implements XCModel and Volvo (Interface)
VolvoXC95 implements XCModel and Volvo (Interface)

line1: Volvo   a = new VolvoXC90();
line2: Volvo   a = new VolvoXC95();
line3: XCModel a = new VolvoXC95();

Если вы видите только строки 1 и 2, вы можете сделать вывод, что VolvoXC90 и VolvoXC95 имеют одинаковый тип (Volvo). Вы не можете сделать вывод, что Volvo является суперклассом или Volvo является интерфейсом.

Если вы видите только line2 и line3, вы можете сделать вывод, что Volvo95 реализует два типа, XCModel и Volvo, в Java вы знаете, что по крайней мере один должен быть интерфейсом. Если бы этот код был написан, например, на C ++, это могли быть оба класса. Поэтому множественное наследование.

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

Представьте себе систему, в которой вы используете класс VolvoXC90 в 200 других классах.

VolvoXC90 v = new VolvoXC90();

Если вам нужно развивать свою систему для запуска VolvoXC95, вам нужно изменить 200 других классов.

Теперь представьте систему, в которой вы используете интерфейс Volvo в 10 000 000 классов.

// Create VolvoXC90 but now we need to create VolvoXC95
Volvo v = new VolvoFactory().newCurrentVolvoModel(); 

Теперь, если вам нужно развивать свою систему для создания моделей VolvoXC95, вам нужно изменить только один класс - Factory.

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

Я рекомендую вам прочитать больше о принципах S.O.L.I.D и прочитать книгу Эффективная Java. У него есть хорошие уроки от опытных инженеров программного обеспечения.

...