ZF + Doctrine 2: тяжелые классы моделей или облегченная модель + сервисный уровень?

Я интегрирую Zend Framework и Doctrine 2 и открываю для себя уровень службы.

Теперь я понимаю (я ошибаюсь?), что у меня есть две возможные архитектуры:

  • модель, в которой классы содержат логику предметной области, т. е. свойства + геттеры/сеттеры + сложные методы.
  • Облегченная модель, в которой классы содержат свойства + геттеры/сеттеры и слой Сервис, содержащий логику предметной области и изменяющий классы модели.

Каковы плюсы/минусы каждого?

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


person Matthieu Napoli    schedule 01.05.2011    source источник
comment
Всегда возможно более двух архитектур   -  person Fatmuemoo    schedule 02.05.2011


Ответы (1)


Что заставляет вас думать, что ваш сервисный уровень является внешним по отношению к вашей модели? Это не так. Фактически, это центральная часть вашей модели, наряду с сущностями, репозиториями и т. д.

Если вы используете Doctine2, вам понадобится сервисный слой. Одна из причин заключается в том, что вы не хотите, чтобы ваши Entities знали об EntityManager (вредит тестируемости). Другой заключается в том, что вы также не хотите, чтобы ваши контроллеры управляли EM (это не работа контроллеров, чтобы знать о постоянстве).

Обычно я использую архитектуру, в которой сервисный уровень является интерфейсом контроллера к модели. Сервисный уровень предоставляет функции, которые работают с сущностями (принимая их как параметры, возвращая их или и то, и другое). Постоянство сущностей скрыто сервисным уровнем. Либо сервисный класс сам управляет EM и репозиториями, либо делегирует их какому-то другому коду, о существовании которого контроллер никогда не узнает.

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

person timdev    schedule 01.05.2011
comment
Отличный и четкий ответ, спасибо, хотя мне трудно понять, почему я теряю ООП... Я имею в виду, что я думаю, что $user->generatePassword() лучше, чем $userService->generatePassword($user), потому что метод применяется к пользователю, а не функция, применяемая к параметр... Вот что я имею в виду под внешним. Для меня это похоже на разницу между ООП (объекты и методы на объектах) и программированием функций. На сервисном уровне объект является просто контейнером данных... - person Matthieu Napoli; 01.05.2011
comment
@matthieu, если ваш метод generatedPassword() генерирует только случайную строку, тогда можно использовать этот метод в вашей сущности; он не создает никаких внешних зависимостей, связанных с постоянством. - person Cobby; 02.05.2011
comment
@matthieu - Entity являются контейнерами данных - они просто причудливые (потому что у них могут быть методы для управления или отчета о своем внутреннем состоянии). generatePassword() может подойти, если только он не полагается на что-то внешнее. Например, если generatePassword() просто генерирует 8 случайных символов и присваивает эту строку $this-›password (или передает ее $this-›setPassword(), которая затем соответствующим образом хэширует ее), это нормально. Это нормально, потому что это влияет только на пароль пользователя и больше ни на что. Теперь, если вы хотите отправить пользователю новый пароль по электронной почте, вы должны сделать это - person timdev; 02.05.2011
comment
[... продолжение] в другом месте. Если вы хотите обсудить это подробнее, пришлите мне электронное письмо по адресу tim-at-‹myusername›.com — этот сайт не предназначен для обмена сообщениями (но, к счастью, электронная почта предназначена). - person timdev; 02.05.2011
comment
Или внешнее сообщение в блоге с веткой комментариев, чтобы другие — такие как я, намек, намек — могли извлечь выгоду из обмена. Меня очень интересует эта дискуссия. ;-) - person David Weinraub; 02.05.2011
comment
Большое спасибо, я начинаю понимать! Я много читаю о сервисном слое (хотя о PHP не так много по сравнению с Java) - person Matthieu Napoli; 03.05.2011
comment
@Matthieu Просто чтобы уточнить предыдущий комментарий @timdev о generatePassword. Скажем, например, у вас есть простой класс с именем String, который содержит общие строковые функции, такие как slugize(), hash() и generatedRandomString(). Также вполне приемлемо для Entity использовать такой класс, поскольку он не связан с постоянством. - person Cobby; 03.05.2011
comment
@Кобби - Точно. В частности, это нормально, потому что эти функции не имеют внешних побочных эффектов. По крайней мере, в моих проектах я не позволяю сущностям делать такие вещи, как отправка электронной почты. На самом деле, я, вероятно, не позволил бы им напрямую обращаться к внешнему API только для чтения. - person timdev; 03.05.2011
comment
@MatthieuNapoli, спасибо, я нашел это обсуждение очень полезным для уточнения моего мышления. Некоторые комментарии timdev станут руководящими принципами архитектуры моего приложения. Заинтересованы в том, чтобы следить за тем, как вы читаете об услугах. Вы готовы опубликовать пару ссылок здесь? - person Steve; 06.08.2014