Как мне структурировать приложение Java, где мне разместить свои классы?

StackOverflow https://stackoverflow.com/questions/7596

  •  08-06-2019
  •  | 
  •  

Вопрос

Прежде всего, я знаю, как создать приложение Java.Но я всегда был озадачен тем, где проводить занятия.Есть сторонники организации пакетов строго по доменному принципу, другие разделяют пакеты по уровням.

У меня самого всегда были проблемы с

  • именование,
  • размещение

Так,

  1. Где вы помещаете константы, специфичные для вашего домена (и какое имя лучше всего подходит для такого класса)?
  2. Где вы помещаете классы для вещей, которые являются как инфраструктурными, так и специфичными для предметной области (например, у меня есть класс FileStorageStrategy, который хранит файлы либо в базе данных, либо, альтернативно, в базе данных)?
  3. Где разместить исключения?
  4. Существуют ли какие-либо стандарты, на которые я могу ссылаться?
Это было полезно?

Решение

Мне действительно понравился Maven's Стандартный макет каталога.

Одна из ключевых идей для меня — иметь два корня исходного кода — один для производственного кода, другой для тестового кода, например:

MyProject/src/main/java/com/acme/Widget.java
MyProject/src/test/java/com/acme/WidgetTest.java

(здесь и src/main/java, и src/test/java являются корнями исходного кода).

Преимущества:

  • Ваши тесты имеют доступ на уровне пакета (или «по умолчанию») к тестируемым классам.
  • Вы можете легко упаковать в JAR только производственные исходные коды, удалив src/test/java в качестве корня исходного кода.

Одно практическое правило относительно размещения классов и пакетов:

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

Другие советы

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

/src - for your packages & classes
/test - for unit tests
/docs - for documentation, generated and manually edited
/lib - 3rd party libraries
/etc - unrelated stuff
/bin (or /classes) - compiled classes, output of your compile
/dist - for distribution packages, hopefully auto generated by a build system

В /src я использую шаблоны Java по умолчанию:Имена пакетов, начинающиеся с вашего домена (org.yourdomain.yourprojectname), и имена классов, отражающие аспект ООП, который вы создаете с помощью класса (см. других комментаторов).Общие имена пакетов, такие как использовать, модель, вид, события тоже полезны.

Я склонен помещать константы для определенной темы в собственный класс, например Константы сеанса или Сервисные константы в том же пакете доменных классов.

Там, где я работаю, мы используем Maven 2, и у нас есть довольно хороший архетип для наших проектов.Целью было добиться хорошего разделения задач, поэтому мы определили структуру проекта, используя несколько модулей (по одному для каждого «слоя» приложения):- общий:Общий код, используемый другими уровнями (например, i18n) - сущности:Доменные объекты - Репозитории:Этот модуль содержит интерфейсы и реализации DAOS - Services -Intf:Интерфейсы для услуг (например, пользовательский сервис, ...) - Services -Impl:Реализации служб (например, userserviceimpl) - Интернет:Все, что касается веб -контента (например, CSS, JSPS, JSF Pages, ...) - WS:веб-сервисы

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

Каждый модуль имеет свой базовый пакет, например, если пакет приложения «com.foo.bar», то мы имеем:

com.foo.bar.common
com.foo.bar.entities
com.foo.bar.repositories
com.foo.bar.services
com.foo.bar.services.impl
...

Каждый модуль соответствует стандартной структуре проекта maven:

   src\
   ..main\java
     ...\resources
   ..test\java
     ...\resources

Модульные тесты для данного слоя легко находят свое место в \src est...Все, что зависит от домена, находится в модуле сущностей.Теперь что-то вроде FileStorageStrategy должно войти в модуль репозиториев, поскольку нам не нужно точно знать, какова реализация.На уровне сервисов мы знаем только интерфейс репозитория, и нас не волнует конкретная реализация (разделение ответственности).

У этого подхода есть несколько преимуществ:

  • четкое разделение задач
  • каждый модуль можно упаковать в виде jar (или war в случае с веб-модулем), что упрощает повторное использование кода (например, мы можем установить модуль в репозиторий maven и повторно использовать его в другом проекте).
  • максимальная независимость каждой части проекта

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

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

То же самое и с вашими пакетами.Их следует сгруппировать по сферам ответственности.В каждом домене есть свои исключения.

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

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

Обычно вершиной вашего дерева пакетов является перевернутое доменное имя (com.domain.subdomain), чтобы гарантировать уникальность, и тогда обычно будет пакет для вашего приложения.Затем разделите это на соответствующие области, чтобы FileStorageStrategy может войти, скажем, com.domain.subdomain.myapp.storage, и тогда могут быть конкретные реализации/подклассы/что угодно в com.domain.subdomain.myapp.storage.file и com.domain.subdomain.myapp.storage.database.Эти имена могут быть довольно длинными, но import сохраняет их все в верхней части файлов, и IDE также могут помочь с этим.

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

На самом деле никакого стандарта как такового нет, просто руководствуйтесь здравым смыслом, а если все станет слишком запутанным, проведите рефакторинг!

Одна вещь, которая мне показалась очень полезной для модульных тестов, — это наличие каталогов myApp/src/, а также myApp/test_src/.Таким образом, я могу поместить модульные тесты в те же пакеты, что и тестируемые ими классы, и при этом легко исключить тестовые примеры при подготовке производственной установки.

Короткий ответ:нарисуйте архитектуру вашей системы в виде модулей, нарисованных рядом, причем каждый модуль вертикально разделен на слои (например,вид, модель, постоянство).Затем используйте структуру вроде com.mycompany.myapp.somemodule.somelayer, например com.mycompany.myapp.client.view или com.mycompany.myapp.server.model.

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

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

  • com.mycompany.myapp.view
  • com.mycompany.myapp.model
  • com.mycompany.myapp.services
  • com.mycompany.myapp.rules
  • com.mycompany.myapp.persistence (или «дао» для уровня доступа к данным)
  • com.mycompany.myapp.util (остерегайтесь, чтобы это слово использовалось как «разное»)

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

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

Одна вещь, которую я делал в прошлом: если я расширяю класс, я стараюсь следовать их соглашениям.Например, при работе с Spring Framework у меня будут классы контроллера MVC в пакете Com.myDomain.myapp.web.servlet.mvc, если я не протягиваю то, что я просто иду с тем, что является самым простым.com.mydomain.domain для объектов домена (хотя, если у вас много объектов домена, этот пакет может оказаться немного громоздким).Что касается констант, специфичных для предметной области, я фактически поместил их как общедоступные константы в наиболее связанный класс.Например, если у меня есть класс «Member» и максимальная длина имени члена, я помещаю его в класс Member.Некоторые магазины создают отдельный класс констант, но я не вижу смысла объединять несвязанные числа и строки в один класс.Я видел, как некоторые другие магазины пытались решить эту проблему, создавая ОТДЕЛЬНЫЕ классы констант, но это кажется пустой тратой времени, а результат слишком запутанным.Используя эту настройку, большой проект с несколькими разработчиками будет повсюду дублировать константы.

Мне нравится разбивать свои классы на пакеты, связанные друг с другом.

Например:Модель Для вызовов, связанных с базой данных

Вид Классы, которые имеют дело с тем, что вы видите

Контроль Классы базовой функциональности

Утилита Любое разное.используемые классы (обычно статические функции)

и т. д.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top