Как мне структурировать Java-приложение, куда мне поместить мои классы? - PullRequest
39 голосов
/ 11 августа 2008

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

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

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

Итак,

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

Ответы [ 10 ]

26 голосов
/ 16 августа 2008

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

12 голосов
/ 12 августа 2008

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

/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 , модель , view , события также полезны.

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

11 голосов
/ 16 сентября 2008

Там, где я работаю, мы используем Maven 2, и у нас есть довольно хороший архетип для наших проектов. Цель состояла в том, чтобы получить хорошее разделение интересов, поэтому мы определили структуру проекта, используя несколько модулей (по одному для каждого уровня приложения): - common: общий код, используемый другими уровнями (например, i18n) - сущности: доменные сущности - репозитории: этот модуль содержит интерфейсы и реализации 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 и использовать его в другом проекте) *
  • максимальная независимость каждой части проекта

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

4 голосов
/ 11 августа 2008

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

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

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

3 голосов
/ 04 сентября 2008

Краткий ответ: начертите архитектуру вашей системы в терминах модулей, нарисованных рядом, с каждым модулем, разрезанным вертикально на слои (например, вид, модель, постоянство). Затем используйте структуру типа 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 голосов
/ 03 сентября 2008

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

3 голосов
/ 11 августа 2008

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

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

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

2 голосов
/ 12 августа 2008

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

0 голосов
/ 12 августа 2008

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

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

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

Управление Основные функциональные классы

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

и т.д.

0 голосов
/ 12 августа 2008

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

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