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

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

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

Ответ 1

Размещение как интерфейса, так и реализации является обычным местом и не кажется проблемой.

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

Возьмем, к примеру, пакет java.util:

Он содержит интерфейсы, такие как Set, Map, List, а также имеет такие реализации, как HashSet, HashMap и ArrayList.

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

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

Если дифференцирование имени интерфейса из реализации необходимо, можно было бы иметь соглашение об именах, чтобы облегчить идентификацию интерфейсов:

  • Префикс имени интерфейса с помощью I. Этот подход применяется с интерфейсами в .NET framework. Было бы довольно легко сказать, что IList является интерфейсом для списка.

  • Используйте суффикс - able. Этот подход часто встречается в Java API, например Comparable, Iterable и Serializable, чтобы назвать несколько.

Ответ 2

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

Посмотрим на этот конкретный экземпляр.

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

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

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

Ответ 3

Во многих рамках, таких как OSGi, вам почти нужно. Я думаю, что это способствует ослаблению сцепления, на упаковке вместо уровня банки.

Ответ 4

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

Ответ 5

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

Ответ 6

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

Ответ 7

У меня мало опыта Java, но мне нравится делать это как хорошую практику в С#/. NET, потому что это позволяет для будущего расширения, когда сборки с конкретными классами, которые реализуют интерфейсы, могут не распространяться полностью вплоть до клиента, поскольку они проксируются посредником factory или через провод в сценарии веб-службы.

Ответ 8

Книга Практическая разработка программного обеспечения: подход к рассмотрению конкретных случаев выступает за размещение интерфейсов в отдельных проектах/пакетах.

Архитектура PCMEF +, о которой говорится в книге, имеет следующие принципы:

  • Принцип нисходящей зависимости (DDP)
  • Принцип восходящего уведомления (UNP)
  • Принцип связи соседей (NCP)
  • Принцип явной ассоциации (EAP)
  • Принцип ликвидации цикла (CEP)
  • Принцип именования классов (CNP)
  • Принцип пакета знакомств (APP)

Описание принципа № 3 и № 7 объясняет, почему это хорошая идея:

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

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

Смотрите эту ссылку: http://comp.mq.edu.au/books/pse/about_book/Ch9.pdf

Ответ 9

Я делаю это по проекту, и он работает хорошо для меня по следующим причинам:

  • Отдельно упакованные интерфейсы и реализации предназначены для другого варианта использования, чем для разных типов карт или наборов. Нет причин иметь пакет только для деревьев (java.util.tree.Map, java.util.tree.Set). Это просто стандартная структура данных, поэтому вместе с другими структурами данных. Однако, если вы имеете дело с играми-головоломкой, которая имеет действительно простой интерфейс отладки и довольно производственный интерфейс, в качестве части своего интерфейса вы можете иметь com.your.app.skin.debug и com.your.app.skin.pretty. Я бы не поставил их в один и тот же пакет, потому что они делают разные вещи, и я знаю, что прибегнув к SmurfNamingConvention (DebugAttackSurface, DebugDefenceSurface, PrettyAttackSurface и т.д.), Чтобы создать неформальное пространство имен для этих двух, если они были в одном пакете.

  • Мое обходное решение проблемы поиска связанных интерфейсов и реализаций, которые находятся в отдельных пакетах, заключается в том, чтобы принять конфигурацию имен для моих пакетов. Например. Я могу использовать все мои интерфейсы в com.your.app.skin.framework и знать, что другие пакеты на одном уровне дерева пакетов являются реализациями. Недостатком является то, что это нетрадиционное соглашение. Честно говоря, я увижу, насколько хорошо это соглашение через 6 месяцев:)

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

  • Мое приложение использует guice и имеет очень много интерфейсов.

Вопросы разработки программы обычно связаны с преимуществами и недостатками, и нет ответа на один размер. Как, почему вы когда-либо использовали эту технику в крошечной 200-строчной программе? Для меня это имеет смысл, учитывая мои другие архитектурные решения, для моей конкретной проблемы.:)

Ответ 10

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

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

Ответ 11

Я предпочитаю их в одном пакете. Не имеет смысла создавать пакет специально для интерфейсов. Это особенно утомительно для команд, которые просто любят свои интерфейсные префиксы и суффиксы (например, "I" и "Impl" для Java).

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

Ответ 12

Обычно я помещаю Interfaces в реализацию, но я могу понять, почему вы можете захотеть сохранить их отдельно. Скажем, например, кто-то хотел переопределить классы на основе ваших интерфейсов, им понадобится jar/lib/etc с вашей реализацией, а не только с интерфейсами. С их помощью вы можете просто сказать "Здесь моя реализация этого интерфейса" и сделать с ним. Как я уже сказал, не то, что я делаю, но я могу понять, почему некоторые могут захотеть.

Ответ 13

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

Ответ 14

Есть много веских причин для того, чтобы поместить интерфейсы в отдельный пакет из реализации. Например, вы можете использовать контейнер, который поддерживает Injection of Dependency для подключения необходимой реализации (-ов) во время выполнения, и в этом случае только интерфейс должен присутствовать во время сборки, и реализация может быть предоставлена ​​во время выполнения. Кроме того, вы можете предоставить несколько реализаций (например, используя mock для тестирования) или несколько версий конкретной реализации во время выполнения ( например, для тестирования A/B и т.д.). Для этих видов использования более удобно пакетный интерфейс и реализацию отдельно.