Должны ли сущности Enterprise Java быть тупыми? - PullRequest
27 голосов
/ 25 февраля 2010

В нашем унаследованном приложении Java EE есть множество классов объектов-значений (VO), которые обычно содержат только методы получения и установки, возможно, equals() и hashCode(). Это (обычно) объекты, которые должны быть сохранены в постоянном хранилище. (Напомним, что в нашем приложении нет EJB-компонентов - хотя может измениться в будущем - и мы используем Hibernate для сохранения наших сущностей.) Вся бизнес-логика для манипулирования данными в виртуальных организациях находится в отдельных классах (не EJB, просто POJO). Мое мышление ОО ненавидит это, так как я верю, что операции над данным классом должны находиться в том же классе. Поэтому у меня есть потребность в рефакторинге, чтобы переместить логику в соответствующие ВО.

Я только что поговорил с коллегой, который гораздо опытнее в Java EE, чем я, и он подтвердил, что глупые сущности, по крайней мере, были рекомендованным способом. Однако он также недавно прочитал мнения, которые ставят под сомнение обоснованность этой позиции.

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

  • он не должен иметь прямой зависимости от уровня данных (например, код запроса должен входить в отдельные DAO)
  • если он напрямую доступен для более высоких уровней или для клиента (например, через SOAP), его интерфейс может быть ограничен

Есть ли еще веские причины не для перемещения логики в мои сущности? Или какие-либо другие проблемы, чтобы принять во внимание?

Ответы [ 8 ]

19 голосов
/ 25 февраля 2010

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

Обратите внимание, что я до сих пор не упомянул термин сущность . Постоянные сущности были популяризированы с помощью ORM, и в настоящее время мы пытаемся использовать постоянные сущности как бизнес-объект DTO и одновременно. То есть сами сущности перемещаются между слоями и уровнями и содержат некоторую логику.

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

Как вы указали, все зависит от зависимостей и того, что вы выставляете. Пока сущности тупые (близкие к DTO), их можно легко изолировать в выделенном банке, который служит API слоя . Чем больше логики вы вкладываете в сущности, тем труднее становится это сделать. Обратите внимание на то, что вы выставляете и от чего зависите (для загрузки класса клиент должен будет иметь также класс зависимостей). Это относится к исключениям, иерархии наследования и т. Д.

Просто для примера, у меня был проект, в котором у сущностей был метод toXml(...), используемый на бизнес-уровне. Как следствие, клиент сущностей зависит от XML.

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

EDIT

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

8 голосов
/ 25 февраля 2010

Я думаю, что ваша точка зрения верна.
Смотрите это больше - http://martinfowler.com/bliki/AnemicDomainModel.html
С JPA, объекты являются легкими объектами. Так что я не думаю, что есть какая-то проблема с логикой в ​​них.

В случае использования с SOAP / веб-сервисами, я бы добавил отдельный фасадный слой.

4 голосов
/ 25 февраля 2010

Помимо упомянутой ранее статьи Фаулера, в книге Эрика Эванса Domain Driven Design (2004) есть полный трактат о моделях богатых и анемичных доменов.

Также, проверьте http://dddcommunity.org/

3 голосов
/ 26 февраля 2010

Правильно, вот краткий обзор отзывов, которые я получил от моего инструктора по Java EE.

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

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

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

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

1 голос
/ 25 февраля 2010

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

Учитывая, что многие проекты имеют смесь младших. программисты и стер. программисты и большая часть работы выполняется младшим, который не понимает (или не заботится) об оптимальной сериализации, гораздо проще иметь эти простые старые объекты Java как «объекты значений», которые в значительной степени просто передают и получают данные поставить логику в другом месте.

Если вам удастся создать архитектуру, в которой логика размещена в бизнес-объекте (то есть VO + Logic), я думаю, что это было бы также лучше. Просто помните, что вся команда находится на одной странице, и они не дублируют код и логику (что никогда не происходит правильно?)

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

1 голос
/ 25 февраля 2010

Соглашение, на которое вы ссылаетесь, заключается в том, чтобы принять модель анемичного домена, в отличие от модели расширенного домена, где сущности - это простые POJO, аннотируемые как бины (@Entity), с минимальным с точки зрения получения и установки. Таким образом, класс с методом toXML () будет рассматриваться как расширенный домен. Я предполагаю, что это помогает сохранять четкое представление о том, что отображается в реляционную базу данных, даже если гранулярность отличается.

Преимущество состоит в том, что существует четкое разделение между логикой и данными (именно здесь философия ОО нарушена). Подход состоит в том, чтобы сгруппировать их в классы бизнес-логики или сервисы. Это соответствует многоуровневой архитектуре с соответствующими уровнями: домен, сервисы, DAO и пользовательский интерфейс.

Это теория.

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

0 голосов
/ 03 апреля 2017

Сущности часто создаются. В таких языках, как Java, такой вещи, как частичный класс, не существует, поэтому мы не можем расширять сущность (не учитывая шаблоны, такие как Visitor). Поэтому, когда вам нужно восстановить свои сущности, вам придется снова добавить бизнес-логику, что совсем не практично.

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

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

0 голосов
/ 13 июня 2013

Я немного программировал на C, и, хотя ООП отлично подходит для упрощения задач путем построения иерархий классов, я все же считаю простой подход на C самым простым и лучшим во многих случаях. В C мы имеем структуры только с открытыми членами, и программист передает такие структуры функциям (в Java такими функциями могут быть, например, статические функции в некотором служебном классе), которые управляют членами. Данные и алгоритм разделены, так как функции не являются членами структур. У меня всегда было ощущение, что VO объекты похожи на структуры в C.

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

Я бы также сослался на эту статью, посвященную C ++, но мне нравится, как этот парень объясняет такие вещи: http://www.gotw.ca/gotw/084.htm В этой статье 2 правила о том, когда делать функцию членом класса:

(из цитаты ниже я пропускаю некоторые вещи, прочитайте оригинал, если хотите все)

  1. Всегда делайте его членом, если он должен быть одним: какие операции должны быть членами, потому что язык C ++ просто говорит об этом (например, конструкторы) или по функциональным причинам (например, они должны быть виртуальными)? Если они должны быть, тогда да, они просто должны быть; дело закрыто.

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

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

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

...