Как моделировать и обрабатывать презентационные DTO для абстрагирования от сложной модели предметной области? - PullRequest
9 голосов
/ 12 апреля 2010

Привет. Я разрабатываю приложение, которое должно работать со сложной моделью предметной области с использованием Hibernate. Это приложение использует Spring MVC, и использование доменных объектов на уровне представления очень грязное, поэтому я думаю, что я должен использовать DTO, которые идут на и с моего сервисного уровня, чтобы они соответствовали тому, что мне нужно в моих представлениях. Теперь давайте предположим, что у меня есть сущность CarLease, свойства которой не являются простыми Java-примитивами, но он состоит из других сущностей, таких как Make, Model и т. Д.

    public class CarLease {
        private Make make;
        Private Model model;
        .
        .
        .
    }

большинство свойств выполнены таким образом, и их можно выбрать с помощью выпадающих списков в представлении jsp, каждое из которых отправит обратно идентификатор на контроллер.

Теперь рассмотрим некоторые стандартные варианты использования: создание, редактирование, отображение

Как вы будете моделировать презентационные DTO, которые будут использоваться в качестве объектов поддержки форм и связи между уровнями представления и обслуживания?

Будете ли вы создавать разные DTO для каждого случая (создавать, редактировать, отображать), вы будете создавать DTO для сложных атрибутов? если да, то где бы вы перевели идентификатор в сущность?

как и где вы будете обрабатывать валидацию, сборку DTO / Domain, что бы вы вернули из методов уровня обслуживания? (создать, редактировать, получить)

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

спасибо заранее.

Ответы [ 3 ]

3 голосов
/ 12 апреля 2010

Для чего это стоит (я разрабатываю на C # .net - но, надеюсь, принципы должны быть полезны для вас) Я определил несколько типов (DTO), которые я использую для обмена данными между бизнесом и данными ярусы; и у меня есть более одного типа на объект / сущность домена. Они определены как простые классы.

Каждый из них построен с учетом конкретной задачи, например:

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

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

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

Архитектурная форма

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

Люди часто суетятся из-за "разделения интересов" - и это действительно мудрый шаг; это относится к DTO в том смысле, что они обмениваются между уровнями (и сервисами, компонентами и т. д.), поэтому всегда может быть некоторая неоднозначность относительно того, где именно провести линию.

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

Что касается сложности, то есть два способа справиться с этим:

  1. Используйте подробное / удобочитаемое соглашение об именах для всех; типы, чтобы вы знали, что это такое; не имеет значения, сколько их - это то, для чего нужен intelli-sense (& docs). Чем интуитивнее, тем лучше.
  2. KISS - будь проще, если можешь; вам придется сбалансировать разумное повторное использование и принцип единой ответственности (SRP).

Вы бы создали DTO сложного свойства основного объекта?

Я обнаружил, что делаю DTO по одной из двух причин:

  1. Есть данные, которые, как я знаю, мне нужно раскрыть (подтолкнуть), и дизайн DTO не представляет никакой сложности: он основан на данных, которые я хочу раскрыть.
  2. Потяните: потребитель знает, чего он хочет, и DTO разработан для удовлетворения этих потребностей.

Поскольку все они определены в общей сборке, ни один компонент не «владеет» ею, это помогает вам думать с точки зрения «домена», а не с точки зрения компонента; в некоторой степени это повлияет на структуру DTO (повторное использование баланса против SRP).

В обоих случаях сделанный DTO может быть специфичным для конкретной потребности или общим; например, DTO, в котором есть только int и строка, не редкость, это то, что вы бы использовали для отправки в выпадающие списки.

Большинство коллекций DTO, которые я отправляю (от DAL до BL), являются специфическими для концепции - не являются общими. Я применяю очень простые правила для них с помощью конструкторов, которые я предлагаю: требуется каждый аргумент. Я не уверен, отвечает ли это на ваш вопрос «Как вы управляете сборкой и проверкой».

1 голос
/ 12 апреля 2010

Рассматривали ли вы принцип разделения ответственности командного запроса (CQRS)? В двух словах, это архитектурный принцип, предусматривающий использование отдельных компонентов для операций чтения и изменения.

Модификации выполняются с использованием команд, отправленных в модель предметной области. Ваш NewCarLeaseDTO выглядит как команда - CreateNewCarLeaseCommand. Они содержат все данные, необходимые для конкретной операции.

С другой стороны, чтение (как для списка, так и для подробностей) выполняется непосредственно в базовом хранилище данных (база данных SQL). Здесь есть много возможностей, начиная от одного и того же хранилища данных, поддерживающего чтение и запись, и заканчивая подключением двух независимых хранилищ данных через инфраструктуру публикации / подписки.

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

Если вы хотите узнать больше о CQRS, я рекомендую прочитать Уди Дахана и Грега Янга.

1 голос
/ 12 апреля 2010

Идея о том, что сервисный уровень должен возвращать DTO вместо объектов EJB, в основном является идеей, предшествующей эпохе EJB3 / JPA. Во время CRUD вы действительно получаете большую выгоду от непосредственной работы с объектами модели (например, сущностями).

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

Поэтому, если вы не разрабатываете под SOA, я бы не рекомендовал работать с DTO для операций CRUD.

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