В каком слое должны быть объекты "Шаблон спецификации" "новыми"?

Итак, я просмотрел несколько постов о шаблоне спецификации здесь и не нашел ответа на этот вопрос.

Мой вопрос, в n-многоуровневой архитектуре, где именно мне должны быть "обновлены" спецификации?

  1. Я мог бы поместить их в мой сервисный уровень (иначе, прикладной уровень, который иногда называют... в основном, чем-то, с чем может поговорить код.aspx), но я чувствую, что, делая это, я позволяю бизнес-правилам вытекать из Домен. Если доступ к объектам Домена осуществляется другим способом (помимо уровня обслуживания), объекты Домена не могут применять свои собственные бизнес-правила.

  2. Я мог бы добавить спецификацию в мой класс Model с помощью инжектора конструктора. Но опять же, это чувствует себя "неправильно". Я чувствую, что единственное, что должно быть внедрено в классы Model, это "сервисы", такие как Caching, Logging, отслеживание грязных флагов и т. Д. И если вы можете избежать этого, используйте Aspect вместо того, чтобы засорять конструкторы Model классы с тоннами сервисных интерфейсов.

  3. Я мог бы внедрить Спецификацию с помощью внедрения метода (иногда называемого "Двойной отправкой"???), и явно сделать так, чтобы этот метод инкапсулировал внедренную Спецификацию, чтобы обеспечить соблюдение ее бизнес-правила.

  4. Создайте класс "Службы домена", который будет принимать спецификацию (и) посредством внедрения конструктора, а затем позволит сервисному уровню использовать Службу домена для координации объекта Домена. Мне кажется, что это нормально, так как правило, предписанное Спецификацией, все еще находится в "Домене", и класс службы домена можно назвать очень похожим на объект домена, который он координирует. Дело в том, что я чувствую, что пишу МНОГО классов и кода, просто чтобы "правильно" реализовать шаблон спецификации.

Добавьте к этому, что для рассматриваемой Спецификации требуется репозиторий, чтобы определить, "удовлетворен" он или нет.

Это может потенциально вызвать проблемы с производительностью, особенно если я использую инъекцию конструктора, b/c потребляющий код может вызвать свойство, которое, возможно, оборачивает спецификацию, а это, в свою очередь, вызывает базу данных.

Так какие-нибудь идеи / мысли / ссылки на статьи?

Где лучшее место для новых и использования спецификаций?

2 ответа

Решение

Короткий ответ:

Вы используете спецификации в основном на вашем уровне обслуживания, так что там.

Длинный ответ: Прежде всего, здесь есть два вопроса:

Где должны жить ваши спецификации, и где они должны быть новыми?

Как и ваши интерфейсы репозитория, ваши спецификации должны находиться на уровне домена, так как они, в конце концов, зависят от домена. Есть вопрос о SO, который обсуждает это на интерфейсах репозитория.

Где они должны быть новенькими, хотя? Ну, я использую LinqSpecs в своих репозиториях, и в большинстве случаев в моем репозитории есть три метода:

public interface ILinqSpecsRepository<T>
{
    IEnumerable<T> FindAll(Specification<T> specification);
    IEnumerable<T> FindAll<TRelated>(Specification<T> specification, Expression<Func<T, TRelated>> fetchExpression);
    T FindOne(Specification<T> specification);
}

Остальные мои запросы построены в моем слое обслуживания. Это предотвращает раздувание репозиториев с помощью таких методов, как GetUserByEmail, GetUserById, GetUserByStatus и т. Д. В моем сервисе я обновляю свои спецификации и передаю их методам FindAll или FindOne моего репозитория. Например:

public User GetUserByEmail(string email)
{
    var withEmail = new UserByEmail(email); // the specification
    return userRepository.FindOne(withEmail);
}

и вот спецификация:

public class UserByEmail : Specification<User>
{
    private readonly string email;

    public UserByEmail(string email)
    {
        this.email = email;
    }

    #region Overrides of Specification<User>

    public override Expression<Func<User, bool>> IsSatisfiedBy()
    {
        return x => x.Email == email;
    }

    #endregion
}

Таким образом, чтобы ответить на ваш вопрос, спецификации новы в слое сервиса (в моей книге).

Я чувствую, что единственное, что должно быть введено в классы Model, это "сервисы"

ИМО, вы не должны вводить что-либо в доменные объекты.

Добавьте к этому, что для рассматриваемой Спецификации требуется репозиторий, чтобы определить, "удовлетворен" он или нет.

Это кодовый запах. Я бы пересмотрел ваш код там. Спецификация определенно не должна требовать хранилища.

Спецификация - это проверка реализации бизнес-правила. Он должен существовать в полной остановке уровня домена.

Трудно дать конкретику о том, как вы это делаете, так как каждая кодовая база отличается, но любая бизнес-логика, по моему мнению, должна быть на уровне предметной области и нигде больше. Эта бизнес-логика должна быть полностью тестируемой и свободно связанной с пользовательским интерфейсом, базой данных, внешними сервисами и другими не доменными зависимостями. Так что я бы определенно исключил 1, 2 и 3 выше.

4 вариант, по крайней мере, спецификация будет жить на уровне вашего домена. Однако обновление спецификаций снова зависит от реализации. Мы обычно используем внедрение зависимостей, поэтому обновление почти всех наших объектов выполняется через контейнер IOC и соответствующий код начальной загрузки (т. Е. Обычно мы проводим приложение свободно). Однако мы никогда не будем напрямую связывать бизнес-логику, например, с классами модели пользовательского интерфейса и тому подобным. У нас обычно есть контуры / границы между такими вещами, как пользовательский интерфейс и домен. Обычно мы определяем контракты на обслуживание домена, которые затем могут использоваться внешними уровнями, такими как пользовательский интерфейс и т. Д.

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

Другие вопросы по тегам