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

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

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

  • нейминг,
  • размещение

Так,

  1. Куда вы помещаете специфичные для вашего домена константы (и какое имя лучше всего подходит для такого класса)?
  2. Где вы размещаете классы для вещей, которые являются как инфраструктурными, так и специфичными для домена (например, у меня есть класс FileStorageStrategy, который хранит файлы либо в базе данных, либо, альтернативно, в базе данных)?
  3. Где поставить исключения?
  4. Есть ли стандарты, на которые я могу сослаться?
11.08.2008 07:45:20
Очевидно, что однозначного ответа нет, но после некоторого использования maven2 я пришел, чтобы оценить данную структуру, и поэтому я объявляю maven ответ как единый. (Это не значит, что остальные ошибаются или что-то в этом роде) Я просто понял, насколько проще не думать о начальных этапах сборки, вы просто помещаете свои источники и ресурсы в эти каталоги, и он компилируется. без создания муравьиных файлов и прочего.
Mauli 15.05.2009 12:51:20
10 ОТВЕТОВ
РЕШЕНИЕ

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

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

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 или SonarJ , который поможет вам устранить их.

28
16.10.2018 17:11:27

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

Аналогично для вас пакеты. Они должны быть сгруппированы по областям ответственности. У каждого домена есть свои исключения.

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

4
11.08.2008 08:00:58

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

Обычно вершина вашего дерева пакетов - это ваше доменное имя в обратном порядке ( 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. Аналогично, интерфейс, определяющий константы, будет в том же пакете.

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

3
11.08.2008 08:24:02

Одна вещь, которую я сделал в прошлом - если я продолжу занятия, я постараюсь следовать их правилам. Например, при работе с Spring Framework у меня будут свои классы MVC Controller в пакете с именем com.mydomain.myapp.web.servlet.mvc. Если я не расширяю что-то, я просто делаю то, что проще. com.mydomain.domain для доменных объектов (хотя, если у вас есть тонна доменных объектов, этот пакет может быть немного громоздким). Для доменных констант я фактически помещаю их как открытые константы в наиболее связанный класс. Например, если у меня есть класс «Member» и константа максимальной длины имени члена, я помещаю его в класс Member. В некоторых магазинах создается отдельный класс Constants, но я не вижу смысла в том, чтобы объединять несвязанные числа и строки в один класс. Я' Мы видели, как некоторые другие магазины пытаются решить эту проблему, создавая классы SEPARATE Constants, но это кажется пустой тратой времени, а результат слишком запутанный. Используя эту настройку, большой проект с несколькими разработчиками будет дублировать константы повсюду.

0
11.08.2008 23:25:44

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

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

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

Функциональные классы Control Core

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

и т.п.

0
12.08.2008 01:28:23

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

2
12.08.2008 03:36:32

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

/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) и имена классов, отражающие аспект ООП, который вы создаете с помощью класса (см. Другие комментарии). Также полезны общие имена пакетов, такие как util , model , view , events .

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

12
12.08.2008 08:00:18

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

3
3.09.2008 12:21:37

Краткий ответ: нарисуйте архитектуру вашей системы в терминах модулей, нарисованных рядом, с каждым модулем, разрезанным вертикально на слои (например, представление, модель, постоянство). Затем используйте такую ​​структуру, как 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 (или 'dao' для уровня доступа к данным)
  • com.mycompany.myapp.util (остерегайтесь этого, как если бы оно было «разное»)

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

3
4.09.2008 13:40:54

Там, где я работаю, мы используем Maven 2, и у нас есть довольно хороший архетип для наших проектов. Цель состояла в том, чтобы получить хорошее разделение интересов, поэтому мы определили структуру проекта, используя несколько модулей (по одному для каждого «уровня» приложения): - общий: общий код, используемый другими уровнями (например, i18n) - объекты: домен entity - repositories: этот модуль содержит интерфейсы и реализации daos - services-intf: интерфейсы для сервисов (например, UserService, ...) - services-impl: реализации сервисов (например, UserServiceImpl) - web: все, что касается веб-контент (например, 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 \ test ... Все, что относится к области, имеет свое место в модуле entity. Теперь что-то вроде FileStorageStrategy должно войти в модуль репозиториев, так как нам не нужно точно знать, что такое реализация. На уровне сервисов мы знаем только интерфейс репозитория, нам все равно, какова конкретная реализация (разделение задач).

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

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

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

11
16.09.2008 15:55:13