Кто должен обрабатывать условия в сложных запросах, средство отображения данных или уровень обслуживания?

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

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

Допустим, мы хотим получить всю книгу, написанную определенным автором, под определенным издателем. Мы могли бы расширить метод BookDataMapper->get() для анализа нескольких условий или написать новый метод, например BookDataMapper->getByAuthorAndPublisher().

Что предпочтительнее, чтобы уровень сервиса вызывал эти [более конкретные] методы напрямую, или чтобы условия были проанализированы перед вызовом более общего метода BookDataMapper->get() с несколькими переданными условиями? В последнем сценарии уровень обслуживания будет выполнять большую часть логической «тяжелой работы», оставляя средство отображения данных довольно простым. Первый вариант сократит уровень обслуживания почти полностью до посредника, оставив условную логику преобразователю данных в таких методах, как BookDataMapper->getByAuthorAndPublisher().

Очевидная проблема, связанная с тем, чтобы позволить уровню сервиса анализировать условия, заключается в том, что некоторая логика предметной области просачивается из средства отображения данных. (это объясняется в связанном вопросе здесь. Однако, если бы уровень сервиса должен был обрабатывать условия, логика не вырвалась бы из уровня модели; контроллер все равно вызовет $book_service->getByAuthorAndPublisher().


person orourkek    schedule 13.08.2012    source источник


Ответы (2)


Шаблон data 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().

Не существует реального способа реализовать эмпирическое правило «Скажи, не спрашивай» для взаимодействия сопоставителя и объекта домена.

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

Обновлять

В моем случае, если вы планируете работать с группами объектов, вам следует иметь дело с разными структурами, а не с простыми объектами домена.

$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 );

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

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

Примечание. В некотором смысле можно сказать, что средство сопоставления связано с шаблонами строителя / фабрики. Цель другая, но подход к решению проблем очень похож.

person tereško    schedule 13.08.2012
comment
Как такой простой DM обработает, например, получение всех пользователей, которые зарегистрировались между двумя датами? Где будут генерироваться предложения WHERE DB? - person orourkek; 14.08.2012
comment
В такой ситуации вы сопоставляете не один объект домена, а их коллекцию. Коллекция, естественно, будет иметь разные сеттеры, а затем простой объект домена, потому что она разработана, чтобы содержать их группу. - person tereško; 14.08.2012
comment
Что ж, аналогичный пример - получение одного пользователя с теми же условиями, с тем же прикрепленным вопросом. - person orourkek; 14.08.2012
comment
Когда вы имеете дело с диапазоном, вы не можете предполагать, что он вернет одну запись. Это просто напрашивается на неприятности. - person tereško; 14.08.2012
comment
очень верно, [непрограммная] абстракция примера ускользнула от меня: P - person orourkek; 14.08.2012
comment
@ tereško В случае коллекций вы создаете класс пользовательской коллекции, чтобы указать критерии? Нравится диапазон дат. Не возражаете добавить примеры? - person Keyne Viana; 24.08.2012
comment
Для простой сцены проекта объединить коллекцию в Mapper, возможно, проще, как ответ @hakre, потому что здесь Collection действует только как предварительный фильтр параметров в Mapper. - person Fwolf; 28.11.2013
comment
Думаю, вы не слышали о SRP. Или, по крайней мере, не поняли, в чем дело. - person tereško; 28.11.2013
comment
Я думаю, что независимо от того, сколько условий на уровне сопоставления, ответственность за уровень сопоставления заключается в получении объекта в соответствии с сопоставителем, эти условия являются просто условиями запроса, а не бизнесом. и уровень обслуживания должен помещать логику, например, если что-то происходит, мы должны использовать метод getByAuthorAndPublisher, другие использовать другие получают метод, это настоящая логика. - person Amitābha; 12.08.2015

Обычно я предпочитаю быть более конкретным, например:

BookDataMapper->getByAuthorAndPublisher($author, $publisher)

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

Если вы сделаете это более динамичным, вы легко можете иметь тенденцию предлагать слишком много функций через интерфейс. Фигово.

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

person hakre    schedule 13.08.2012
comment
Интересно - это просто предпочтение или есть какие-то передовые практики и / или документация в поддержку этого? Очевидно, утечка логики / функциональности может быть оценена в соответствии с передовой практикой, но ее также можно контролировать и уточнять, чтобы вообще не просачиваться из уровня модели, верно? - person orourkek; 14.08.2012
comment
Фу, я не из тех, кто занимается академическими исследованиями, я не знаю, есть ли за этим документированные передовые практики. Когда я выступаю в роли потребителя какого-то слоя - например, устройство отображения данных - мне нравится иметь чистый и лаконичный интерфейс, и он на самом деле конкретен. Никаких скрытых контрактов через более или менее динамические объекты значений или параметров. Я имею в виду, что в противном случае я могу сразу выполнить некоторый SQL, если мне нужно больше гибкости. Но это разрушит слой. Так что нарисуйте линию и не беспокойтесь. - person hakre; 14.08.2012
comment
Могу добавить: в некоторых реализациях есть средства поиска рядом с картографами. Те заботятся о поиске объектов, картографы по-прежнему заботятся о отображении данных. Иногда их можно собрать вместе, иногда лучше разделить их, чтобы можно было расширить их, если количество искателей будет расти. - person hakre; 14.08.2012
comment
Я предпочитаю этот ответ принятому. Он больше соответствует подходу к репозиторию, который гарантирует, что такая логика поиска, которая актуальна в бизнес-области, например поиск книг по автору и издателю, как в показанном примере. Такие методы должны предоставляться API репозитория (или API отображения данных, если хотите). Это делает логику поиска более очевидной и предотвращает ее разброс по разным другим классам (например, контроллерам). - person afh; 25.08.2020