Интерфейсы (интерфейс/абстрактный класс) не являются абстракциями?

В последнее время я читаю сообщения, в которых говорится о предполагаемом неправильном представлении о том, что интерфейсы являются абстракциями. Один такой пост http://blog.ploeh.dk/2010/12/02/InterfacesAreNotAbstractions.aspx

Я немного смущен. Если у меня нет интерфейсов (интерфейс/абстрактный класс), то как я буду вводить свои зависимости и издеваться над ними?

Кроме того, я слышал, что люди говорят о том, что не используют интерфейсы, у которых есть только один разработчик. Как этот блог здесь - http://simpleprogrammer.com/2010/11/02/back-to-basics-what-is-an-interface/

Теперь все это, не нарушает ли он принцип - Программа для интерфейса, а не для реализации?

Ответ 1

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

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

Вы должны быть уверены, что ваш код не зависит от внутренних данных других классов.

Ответ 2

Я бы сказал, что не согласен со многими пунктами в связанных статьях:

  • интерфейсы - это контракты. Контракт состоит из двух частей: подписи метода (чисто синтаксической) и документации.

  • интерфейсы - это абстракции. Я не видел примера нарушения LSP. Пример IRectangle не является хорошим. То же самое можно сказать о Set extends Collection, где добавление дубликатов запрещено. Если вам передан Collection, вы можете быть удивлены, что он запрещает дубликаты. С интерфейсами Collection это заботится, документируя, что разработчики могут добавлять ограничения.

  • Непосредственные абстракции неизбежны. Но это полностью зависит от дизайнера. И btw "интерфейсы являются негерметичными абстракциями" означает, что они являются абстракциями.

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

  • Очень хороший пример из нашего текущего проекта - изначально у нас есть только одна реализация DAO - одна взяла материал из базы данных. Но позже мы переключили некоторые операции на выделенную поисковую систему. Мы добавляем еще одну реализацию DAO, и там мы идем. Таким образом, интерфейс с одной реализацией первоначально окупился.

  • Btw, изначально SortedSet имел только одну реализацию в JDK - TreeSet. Теперь у него два. И многое другое из внешних библиотек.

  • наконец, интерфейсы (как языковая конструкция) - это способ описания функциональности класса с дополнительной особенностью отказа от реализации любой реализации. То есть - интерфейсы трудно использовать для абстракции.

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

Ответ 3

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

Здесь часто используется случай, когда у меня есть только один разработчик (на мой взгляд): у вас есть компонент Swing, скажем, CarComparisonResultsPanel, который позволяет пользователю видеть результаты сравнения между легковые автомобили. Как пользователь панели, я бы предпочел иметь интерфейс CarComparisonResult только с getCarSimilarities() и getCarDifferences(), чем реализация JPanel, которая реализует эти методы, а также десятки других.

РЕДАКТИРОВАТЬ: Чтобы сделать мой "не делай этого", немного более ясны, это несколько примеров переусердства: интерфейсы для фабрик, сборщиков, классов помощников/утилит, компонентов графического интерфейса, которые не добавляют соответствующие общедоступные методы их родителям,...

Ответ 4

Принципы программирования для интерфейса не обязательно оставлять для взаимодействия только с ситуациями. Когда вы разрабатываете свои интерфейсы, общие вопросы, которые вы задаете, - "Где я ожидаю, что это будет поглощено? К кому? И с какой целью?" Вопросы, которые следует задать даже при создании классов реализации.

Возможно, при разработке интерфейса вы осознаете, что вам действительно не нужно делать этот интерфейс, и для тестирования достаточно для перегрузки и наследования. Как упоминалось в первой статье, если вы последовательно контактируете с соотношением 1:1 между объектами и интерфейсами без какой-либо цели, кроме "Я программирую против интерфейсов", вы просто делаете беспорядок своего кода.

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