Вопрос: DDD: договор репозитория


Я читал в разных местах, что одним из важных требований в DDD является наличие ограниченного контракта для репозитория:

findByName(string name)
findByEmail(string email)
etc.

И не предоставлять общий интерфейс запросов:

findBySpecification(Specification spec)

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

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

Предположим, у меня есть форма, которая позволяет искать сообщения в блоге ключевое слово , от Дата , от автор , так далее.

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

findByKeyword(string keyword)
findByDateRange(Date from, Date to)
findByKeywordAndDateRange(string keyword, Date from, Date to)
findByDateRangeAndAuthor(Date from, Date to, User author)
etc.

Я что-то упустил или это одно из исключений из правила?


4


источник


Ответы:


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

Filter filter = new FilterBuilder()
    .WithinDateRange(dateRange)
    .IncludingKeywords("politics", "news")
    .ByAuthor("John Smith")
    .Build();

blogs.FindByFilter(filter);

Обратите внимание, что код, создающий фильтр, может находиться вне домена. Потому что это не будет нарушать какие-либо правила домена. Что делать, если есть правило вроде «Блоги, опубликованные анонимным автором, должны быть одобрены модератором» ? Хотя это может быть выражено с помощью фильтра, это будет вытеснять часть бизнес-логики. Будет более целесообразно включить это правило в код домена и иметь специальный метод репозитория, например:

blogs.RequireModeratorAttention();

2



Шаблон репозитория имеет два основных преимущества:

  1. Он отделяет ваше приложение от вашего уровня сопротивления и идиомы.
  2. Он централизует и ограничивает доступ к данным с четко определенными и понятными сегментами домена (методы доступа к данным в репозитории имеют четко определенный результат и могут быть легко проверены).

Если вы используете экземпляр шаблона спецификации, предоставленный вашим уровнем персистентности (например, NHibernate Criteria), вы отрицаете преимущество. Используя шаблон спецификации вообще (даже тот, который вы катитесь сами), опускает преимущество второго.

При этом в некоторых ситуациях, таких как поисковые интерфейсы, требуется спецификация - просто убедитесь, что вы сами катите.


1



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

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

Если у вас есть команда, которая изменяет адрес пользователя, лучше иметь репозиторий с методом FindUserById, чем иметь какой-то волшебный код Hibernate на уровне приложения. Для этого есть две причины.

  • Вы можете протестировать прикладной уровень с помощью слоя persistence (хранилища) издевались
  • Уровень приложения - это то, о чем вы заботитесь потому что это бизнес-логика

Вам не нужно все это, чтобы просто получить некоторые данные для пользовательского интерфейса. Я бы предложил использовать специализированные классы «Finder», которые могут даже жить в слое пользовательского интерфейса. Они могут работать либо по абстрактной «спецификации», либо (даже лучше) на голом Hibernate (или вашем любимом ORM). Я написал сообщение в блоге об этом подходе Вот ,


1