Интерфейсы должны быть помещены в отдельный пакет? [закрытый]


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

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

14 65

14 ответов:

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

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

возьмем для примера java.util пакет:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  1. принцип нисходящей зависимости (DDP)
  2. принцип восходящего уведомления (UNP)
  3. принцип связи с соседями (NCP)
  4. Явные Ассоциации Принцип (ВП)
  5. принцип исключения цикла (CEP)
  6. принцип именования классов (CNP)
  7. знакомство принцип пакета (приложение)

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

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

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

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

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

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

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

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

  • отдельно упакованные интерфейсы и реализации предназначены для другого варианта использования, чем для различных типов карт или наборов. Нет причин иметь пакет только для деревьев (java.утиль.дерево.Карта, Ява.утиль.дерево.Набор.) Это просто стандартная структура данных, поэтому поместите ее вместе с другими структурами данных. Однако, если вы имеете дело с головоломкой, которая имеет действительно простой интерфейс отладки и довольно производственный интерфейс, в качестве части его интерфейса вы можете иметь com.ваш.приложение.кожа.отладка и com.ваш.приложение.кожа.хорошенький. Я бы не стал помещать их в один и тот же пакет, потому что они делают разные вещи, и я знаю, что прибегну к некоторым SmurfNamingConvention (DebugAttackSurface, DebugDefenceSurface, PrettyAttackSurface и т. д.), Чтобы создать некоторое неформальное пространство имен для двух, если они были в одном пакете.

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

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

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

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

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

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

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

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

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

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

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