Методология интерфейсов Java: должен ли каждый класс реализовывать интерфейс? - PullRequest
19 голосов
/ 17 апреля 2010

Я программировал на Java для нескольких курсов в университете, и у меня есть следующий вопрос:

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

Редактировать: Лично мне нравится идея использовать интерфейсы для всего как методологии и привычки, даже если это явно не выгодно. Eclipse автоматически создал файл класса со всеми методами, поэтому он все равно не тратит время.

Ответы [ 13 ]

23 голосов
/ 17 апреля 2010

Вам не нужно создавать интерфейс, если вы не собираетесь его использовать.

Обычно вам нужен интерфейс, когда:

  • Ваша программа предоставит несколько реализаций для вашего компонента. Например, реализация по умолчанию, которая является частью вашего кода, и фиктивная реализация, которая используется в тесте JUnit. Некоторые инструменты автоматизируют создание фиктивной реализации, например, EasyMock.
  • Вы хотите использовать внедрение зависимостей для этого класса с такой средой, как Spring или JBoss Micro-Container. В этом случае рекомендуется указать зависимости одного класса с другими классами с помощью интерфейса.
19 голосов
/ 17 апреля 2010

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

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

8 голосов
/ 18 апреля 2010

Каждый класс реализует интерфейс (то есть контракт), поскольку он предоставляет не приватный API. Нужно ли вам представлять интерфейс отдельно, как интерфейс Java, зависит от того, является ли реализация «концепцией, которая меняется».

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

Некоторые люди будут кричать «ЯГНИ», предполагая, что у вас есть полный контроль над изменением кода, если позже вы обнаружите новое требование. Другие люди будут справедливо бояться, что им нужно будет изменить неизменяемый - опубликованный API.

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

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

В некоторых языках (например, C ++, C #, но не в Java) вы можете получить выигрыш в производительности, если ваш класс не содержит виртуальных методов.

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

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

5 голосов
/ 17 апреля 2010

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

Если в вашей программе нет необходимости иметь более 1 реализации для данного класса, вам не нужен интерфейс. Например, в простой шахматной программе, которую я написал, мне нужен только один тип объекта Board. Шахматная доска - это шахматная доска - это шахматная доска. Создание интерфейса Board и его реализация потребовали бы больше кода для написания и поддержки.

Так легко переключиться на интерфейс, если он вам понадобится.

4 голосов
/ 18 апреля 2010

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

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

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

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

3 голосов
/ 17 апреля 2010

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

2 голосов
/ 18 апреля 2010

Чтобы ответить на вопрос ОП очень прямо: нет, не все классы должны реализовывать интерфейс. Как и во всех вопросах дизайна, это сводится к лучшему суждению. Вот несколько правил, которым я обычно следую:

  • чисто функциональные объекты наверное не нужно (например, шаблон, CharMatcher - хотя последний реализует предикат, это является вторичным по отношению к своей основной функции)
  • Чистые носители данных, вероятно, не нужны (например, LogRecord, Locale)
  • Если вы можете представить другую реализацию данной функциональности (скажем, в памяти Кэш против дискового кэша), попробуйте изолировать функциональность в интерфейс. Но не заходите слишком далеко, пытаясь предсказать будущее.
  • Для целей тестирования это очень удобно, когда занятия, которые делают Потоки ввода / вывода или запуска легко поддаются моделированию, поэтому что пользователи не платят штраф, когда запустить свои тесты.
  • Там нет ничего хуже, чем интерфейс, который протекает основная реализация. Обратите внимание, где вы проводите линию, и убедитесь, что Javadoc вашего интерфейса нейтрален в этом отношении. Если это не так, вам, вероятно, не нужен интерфейс.
  • Вообще говоря, это предпочтительнее для классы предназначены для общественного потребления за пределами вашего пакета / проекта реализовать интерфейсы, чтобы ваш пользователи менее привязаны к вашему Реализация du jour.

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

2 голосов
/ 17 апреля 2010

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

1 голос
/ 17 апреля 2010

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

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

1 голос
/ 17 апреля 2010

Хороший способ изучения того, что считается хорошими методологиями, особенно когда речь идет о разработке структуры кода, - это посмотреть на свободно доступный код. В случае с Java очевидным примером является рассмотрение системных библиотек JDK .

Вы найдете много примеров классов, которые не реализуют какие-либо интерфейсы или предназначены для непосредственного использования, например, java.util.StringTokenizer.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...