Подтвердить что ты не робот

Объекты DAO и модельные объекты

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

  • Контроллер создает объект User и передает его в UserDAO, чтобы сохранить его в базе данных

  • Контроллер создает объект User, а в его конструкторе пользовательский объект делает вызов userDAO, чтобы сохранить себя в базе данных

  • Это запах кода, и вам не хватает дополнительного класса "UserManager", который контроллер попросит создать пользователя. UserManager отвечает за создание пользователя и просит UserDAO сохранить его

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

4b9b3361

Ответ 1

Из моего опыта работы с DAO первый подход является единственным правильным. Причина в том, что у него есть четкие обязанности и он создает наименьший беспорядок (ну, некоторые очень уважаемые программисты считают, что DAO сами по себе являются беспорядками. Адам Бьен видит исходную модель DAO, уже реализованную в EntityManager, а дальнейшие DAO - в основном ненужные "трубы" )

Подход 2 связывает модель с DAO, создавая "восходящую зависимость". Я имею в виду, что обычно модели распространяются как отдельные пакеты и являются (и должны быть) незнакомыми с деталями их персистентности. Аналогичным образом описывается шаблон Active Record. Он широко используется в Ruby on Rails, но не реализован с одинаковой элегантностью и простотой на Java.

Подход 3 - что должно быть точкой UserManager? В вашем примере Менеджер выполняет 2 задания - он выполняет обязанности пользователя factory и является прокси для запросов на сохранение. Если это factory, и вам это нужно, вы должны называть его UserFactory, не налагая на него дополнительных задач. Что касается прокси - зачем вам это нужно?

ИМХО большинства классов с именем ...Manager имеют запах. Само название предполагает, что класс не имеет четкой цели. Всякий раз, когда у меня появляется желание назвать класс ...Manager, это сигнал для меня, чтобы найти более подходящее имя или подумать о моей архитектуре.

Ответ 2

Объект доступа к данным (DAO) следует использовать ближе к уровню доступа к данным вашего приложения. Объект доступа к данным фактически выполняет операции доступа к данным. Таким образом, это часть уровня доступа к данным.

Уровни архитектуры до DAO могут различаться в проектах.

Контроллеры в основном предназначены для управления потоком запросов. Таким образом, они близки к пользовательскому интерфейсу. Хотя диспетчер, обработчик - плохая идея, мы могли бы добавить слой между контроллером и DAO. Таким образом, контроллер будет предварительно обрабатывать данные, поступающие с запроса или выхода (конфиденциальность данных, безопасность, локализация, i18n, преобразование в JSON и т.д.). Он отправляет данные в службу в виде объектов домена (Пользователь в этом случае). Служба будет вызывать некоторую бизнес-логику для этого пользователя или использовать ее для какой-либо бизнес-логики. И он передал бы его DAO.

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

Ответ 3

Предполагая, что контроллер означает "C" в MVC, ваш третий вариант - правильный подход. Вообще говоря, код контроллера расширяет или следует соглашениям фреймворка. Одним из идеалов MVC является обмен файлами, который действительно является контроллером, должен быть относительно простым. Контроллеры должны просто перемещать данные вперед и назад между слоями модели и представления.

С точки зрения модели контроллеры должны взаимодействовать с уровнем обслуживания - контекстной границей - в передней части доменной модели. Объект UserManager был бы примером части, которую вы бы рассматривали как часть вашего уровня сервиса - это общедоступный API модели домена.

Ответ 4

Для первого подхода; IMHO, контроллер, вызывающий метод на объекте DAO, не является хорошим дизайном. Контроллеры должны запрашивать объекты уровня сервиса "service". Как эти "службы" сохраняют данные, это не проблема для контроллера.

Для второго подхода; иногда вам может понадобиться просто создать объект, поэтому обязанность конструктора и постоянная работа не должны быть тесно связаны таким образом.

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

Но для Play, сопутствующие объекты классов case также являются хорошим кандидатом для использования в качестве DAO. Одиночный характер этих объектов делает его хорошим кандидатом.

case class TicketResponse(appId: String, ticket: String, ts: String)

object TicketResponse{
  implicit val ticketWrites = Json.writes[TicketResponse]

  def save(response: TicketResponse) = {

    val result = DB.withConnection {
      implicit connection =>

        SQL("insert into tickets(ticket, appid, ts)"
          +   " values ({ticket},{appid},{ts})")
          .on('ticket -> response.ticket, 'appid -> response.appId, 'ts -> response.ts).executeInsert()
    }

  }

}