2010-12-09 3 views
10

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

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

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

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

ответ

5

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

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

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

+0

* Когда мы говорим «интерфейс» с точки зрения программирования для интерфейса. Такой интерфейс означает внешние методы и свойства класса. Он не должен быть интерфейсом на уровне языка. * Итак, я все время ошибался? Итак, конкретный класс может быть интерфейсом по вашему мнению? – Sandbox

+4

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

+0

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

3

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

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

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

+0

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

+0

Как решить, не переусердствовать? Я имею в виду, что с вашим клиентским кодом, ссылающимся на интерфейсы/абстрактные классы, вы всегда можете поменять реализацию во время выполнения. Кроме того, если у вас нет интерфейсов, как вы собираетесь ими издеваться? Эти две причины заставляют меня думать, что интерфейсы/абстрактные классы совершенно верны во всех случаях. – Sandbox

+0

У меня есть серия обратных ссылок на статьи в моем блоге http://simpleprogrammer.com, вникающие в подробности о интерфейсах и этой точной теме, погружения в DI и IoC и т. Д., Вы можете проверить это. –

0

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

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

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

+0

Я бы сказал, что перегрузка и наследование только для целей тестирования далеко, намного хуже, чем создание интерфейса 1: 1. По наследству вы вводите новую сложность в свой публичный API и открываете множество возможностей для нарушения поведения вашего класса. Интерфейс 1: 1, по крайней мере, не имеет таких побочных эффектов. – NOtherDev

5

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

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

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

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

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

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

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

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

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

+1

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

+0

, как я уже сказал, издевательства могут быть сделаны и по конкретным классам (по крайней мере, в Java есть несколько мощных фреймворков). Однако я не думаю, что неправильно использовать mocks на интерфейсах. Это разная реализация одной и той же концепции, не так ли? Тот факт, что он используется в конкретной среде (unit-test), ничего не принимает от этого - он по-прежнему является интерфейсом с 2 действительными реализациями. – Bozho

+0

Кроме того, вы не должны использовать вспомогательные классы, они не имеют определенной ответственности. Они нарушают ОО. –

Смежные вопросы