этот вопрос очень помог мне немного разобраться в моем замешательстве, но мне трудно найти надежные источники того, какими должны быть точные ограничения уровня сервиса.
В этом примере предположим, что мы имеем дело с книгами, и мы хотим получить книги от автора. BookDataMapper
может иметь общий метод get()
который принимает условия (условия), такие как уникальный идентификатор книги, имя автора и т. Д. Эта реализация довольно тривиальна (логически), но что, если мы хотим иметь несколько условий, требующих более сложный запрос?
Допустим, мы хотим, чтобы вся книга была написана определенным автором под определенным издателем. Мы могли бы расширить метод BookDataMapper->get()
для анализа нескольких условий, или мы могли бы написать новый метод, например BookDataMapper->getByAuthorAndPublisher()
.
Желательно ли, чтобы сервисный уровень вызывал эти [более конкретные] методы напрямую или BookDataMapper->get()
условия, прежде чем вызывать более общий BookDataMapper->get()
с несколькими условиями? В последнем сценарии сервисный уровень будет делать больше логического «тяжелого подъема», оставив карту данных довольно простой. Первый вариант почти полностью BookDataMapper->getByAuthorAndPublisher()
бы сервисный уровень только к среднему человеку, оставив условную логику в BookDataMapper->getByAuthorAndPublisher()
данных в таких методах, как BookDataMapper->getByAuthorAndPublisher()
.
Очевидная забота о том, чтобы позволить сервисному слою анализировать условия, заключается в том, что некоторые из логики домена выходят из устройства отображения данных. (это объясняется в связанном вопросе здесь.Однако, если сервисный уровень должен был обрабатывать условия, логика не выходила бы из уровня модели: контроллер будет вызывать $book_service->getByAuthorAndPublisher()
независимо.
Картограф данных отображает только то, что он должен делать, а не как он должен быть реализован.
Поэтому все ответы в этой теме следует рассматривать как субъективные, поскольку они отражают индивидуальные предпочтения каждого автора.
Я обычно стараюсь максимально упростить интерфейс mapper:
fetch()
, извлекает данные в объекте или коллекции домена, save()
, сохраняет (обновляет существующие или вставляет новый) объект или коллекцию домена remove()
, удаляет объект или коллекцию домена со среды хранения Я сохраняю условие в самом объекте домена:
$user = new User; $user->setName( 'Jedediah' ); $mapper = new UserMapper; $mapper->fetch( $user ); if ( $user->getFlags() > 5 ) { $user->setStatus( User::STATUS_LOCKED ); } $mapper->save( $user );
Таким образом, вы можете иметь несколько условий для извлечения, сохраняя чистоту интерфейса.
Недостатком этого было бы то, что вам нужен публичный метод для извлечения информации из объекта домена, чтобы иметь такой метод fetch()
, но вам все равно понадобится выполнить save()
.
Не существует реального способа реализации правила «Tell Do not Ask» для взаимодействия с картой и доменом.
Что касается «Как убедиться, что вам действительно нужно сохранить объект домена?» , который может произойти с вами, он был рассмотрен здесь , с обширными примерами кода и некоторыми полезными битами в комментариях.
В случае, если вы планируете иметь дело с группами объектов, вы должны иметь дело с различными структурами, а не с простыми объектами домена .
$category = new Category; $category->setTitle( 'privacy' ); $list = new ArticleCollection; $list->setCondition( $category ); $list->setDateRange( mktime( 0, 0, 0, 12, 9, 2001) ); // it would make sense, if unset second value for range of dates // would default to NOW() in mapper $mapper = new ArticleCollectionMapper; $mapper->fetch( $list ); foreach ( $list as $article ) { $article->setFlag( Article::STATUS_REMOVED ); } $mapper->store( $list );
В этом случае коллекция представляет собой прославленный массив, способный принимать разные параметры, которые затем используются в качестве условий для картографа. Он также должен позволить картографу в приобретенный список изменить объекты домена из этой коллекции, когда сборщик пытается сохранить коллекцию.
Преобразователь в этом случае должен иметь возможность создавать (или использовать запрограммированные) запросы со всеми возможными условиями (как разработчик вы будете знать все эти условия, поэтому вам не нужно работать с бесконечным набором условий) и обновить или создать новые записи для всего несохраненного объекта домена, в котором содержится коллекция.
Примечание. В каком-то аспекте вы можете сказать, что обработчик связан с шаблонами построителя / фабрики. Цель разная, но подход к решению проблем очень схож.
Я обычно предпочитаю, чтобы это было более конкретным, например:
BookDataMapper->getByAuthorAndPublisher($author, $publisher)
Это потому, что мне не нужно повторно изобретать SQL. База данных лучше для этого, и картографист данных позаботится о том, чтобы остальная часть приложения не нуждалась в том, чтобы знать что-либо о том, как вещи хранятся или задаются в бетоне.
Если вы сделаете это более динамичным, вы можете легко иметь тенденцию предлагать слишком много функций через интерфейс. Нехорошо.
И взгляните на свое приложение. Вы увидите, что не так много будет задаваться по-другому. Для основной части данных, которая обычно составляет около 5-10 подпрограмм, если вообще. Это написано гораздо быстрее, чем даже думать о какой-то динамической системе, которая в любом случае будет принадлежать ее собственному слою.