Архитектура: лучшие методы управления моделями без загрязнения POJO? И без повторения кода котельной плиты во всем мире

Это проблема, с которой мы часто сталкиваемся. Для решения этой проблемы должны быть некоторые рекомендации...

Упрощенный вопрос

Где лучшее место для размещения общего кода, который управляет POJO?

такое, что:

  • У POJO есть только свойства и геттеры/сеттеры.
  • тот же код манипуляции модели не повторяется "везде"
  • очень ясно, какие классы отвечают за управление моделью

Фон

У нас есть схема, которая определяет наш домен. Из этого мы создаем "чистую" модель, состоящую из простых объектов (POJO), которые поступают из JAXB.

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

Пример

Позвольте использовать продуктовый магазин в качестве общего примера. Объекты модели состоят из таких вещей, как:
Products, Aisle, Shelf, Employee, WorkSchedule, Vendor

Обычные манипуляции с моделью состоят из таких вещей, как:
findManagerWorkingOnDay(day, schedule), findAisleForProduct(apples), countItemsOnShelf(topShelf), product.isModified(), removeProductFromVendor(apples, vendor)

Мы не хотим "загрязнять" наш POJO поставщика с помощью функции типа removeProductFromVendor. Аналогично, мы не обязательно хотим расширять каждый объект модели, просто добавив свойство isModified, чтобы наш графический интерфейс мог знать, что "включить/отключить" кнопку сохранения.

Или мы?

Резюме

Как только объект модели находится в памяти, кто должен нести ответственность за его манипулирование - например, для перебора списка "дежурных сегодня" и найти того, кто является "менеджером?"

В этих случаях вызовы базы данных чрезмерны, потому что у нас уже есть все, что нам нужно в памяти (например: мы уже обращались к DataStore и нам нужно работать с объектами результата во всем приложении). В идеале этот код будет доступен для любого объекта, у которого был, например, список сотрудников.


В плане лучшей практики, где идеальное место для статического метода:
public static Employee findManager(List<Employee> employeesOnDuty);

который будет перебирать список сотрудников (POJO) и возвращать первый, где employee.title.toLowerCase().contains("manager")

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

Ответ 1

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

Звучит как задание для набора подклассов Decorator, или, как предлагает Кен, фасады.

Мне нравятся декораторы, потому что теперь вы просто ссылаетесь на свое pojo вашего поставщика по имени класса декоратора, которое затем будет иметь добавленное поведение (isModified, searchByName и т.д.), все в одном месте.

Ответ 2

Насколько я понимаю, это похоже на то, что ваши модели POJO - это только данные (или вы хотите сохранить их таким образом). Почему бы не создать объекты фасада, такие как Query, Count или другая именованная функциональная группировка, которая скрывает всю связанную с вами механику ваших алгоритмов манипуляции?

Это не будет загрязнять POJO, что похоже на то, что вы хотите избежать.

Ответ 3

В подобной ситуации мы решили продвигать все "функции" (поведения) в качестве граждан первого класса нашей объектной модели.

Итак, теперь у нас есть отдельные пакеты, один с POJO, и один, где у нас есть функции Object (aka Processors), возлагающие функции на эти объекты.

Например, объект Контракт как POJO и ContractBilling, ContractFinder, ContractCloser и т.д. в качестве процессоров. Большинство из них работают по Контракту или списку контрактов.

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

Ответ 4

несмотря на то, что вопрос сейчас на 1 год, надеюсь, что он может оказаться полезным для некоторых других людей. Таким образом, ваш хочет поддерживать POJO и по-разному относиться к нему, чтобы эти утверждения имели место:  а) POJO имеют только свойства и геттеры/сеттеры,  б) один и тот же код манипуляции с моделью повторно используется,  c) ясно, какие классы отвечают за манипулирование моделью широко признано и достигается через разделение приложения на уровни, то есть:

  • ваши POJO - это простая модель, содержащая поля/свойства и просто getters/setters;
  • бизнес-логика, связанная с манипуляциями с моделью, помещается в сервисный уровень - в вашем случае все, что касается манипуляций на примере. Сотрудник может быть выделен в EmployeeService (и, следовательно, повторно использован во многих местах);
  • все относящиеся к стойкости идут на уровень DAO, например. EmployeeDAO;
  • для обмена данными между уровнями, например. вид и обслуживание - DTO (объекты передачи данных).

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

Надеюсь, это поможет.

Ответ 5

Я полагаю, что для таких операций, как find *, они относятся к классам сервисов; но для "isModified" класс обслуживания не поможет, он должен быть в самом pojo, если, конечно, модификация также не происходит через класс обслуживания. Соответствующий класс обслуживания может затем поддерживать состояние таких объектов в коллекции.