Сравнение шаблона спецификации, предикатов Func и труб и фильтров

Я делаю некоторые R&D работы, и как таковой изучаю шаблоны проектирования. Недавно я читал о шаблоне спецификации и был упомянут этой большой статьи.

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

рассмотрим следующий контракт интерфейса для сервисного уровня:

public interface IFooDataService
{
   ICollection<Foo> GetFoosBySpecification(Specification<Foo> specification);
   ICollection<Foo> GetFooByPredicate(Func<Foo,bool> predicate);
   ICollection<Foo> GetFooBySearchArgs(FooSearchArgs searchArgs);
}

Итак, некоторые начальной точки:

  • все три возвращают коллекцию объектов Foo
  • все трое принимают один аргумент
  • метод спецификации ограничивает доступ к специфическим требованиям
  • метод предикатов в основном не имеет ограничений
  • метод поиска args ограничивает доступ к определенным требованиям

Теперь о реализации:

public ICollection<Foo> GetFoosBySpecification(Specification<Foo> specification)
{
    return fooDataRepository
            .Find()
            .Where(f => specification.IsSatisfiedBy(f))
            .ToList();
}

public ICollection<Foo> GetFooByPredicate(Func<Foo, bool> predicate)
{
    return fooDataRepository
            .Find()
            .Where(predicate)
            .ToList();
}

public ICollection<Foo> GetFooBySearchArgs(FooSearchArgs searchArgs)
{
    return fooDataRepository
            .Find()
            .WhereMeetsSearchCriteria(searchArgs)
            .ToList();
}

указывает на реализация:

  • все три чрезвычайно просты в реализации (одна строка прикованного кода)
  • спецификация и поиск отфильтрованные Args реализованы извне.
  • метод поиска args просто использует метод расширения IEnumerable для проверки args

Итак, это, как говорится, при каких условиях вы бы использовали один из трех методов?

мои мысли о спецификации шаблона:

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

мои мысли о методах расширения (трубы и фильтры):

  • "весомый" в логике, но все же результат в той же простоте.
  • изолировать логику запроса от уровня сервиса до статических методов
  • по-прежнему требует "отражения" сортировки (проверка предоставленных поисковых аргов и создание запроса)
  • позволяет сначала кодировать архитектуру (репозиторий, уровень обслуживания), не думая о конкретном бизнесе требования (что удобно в некоторых случаях)

мои мысли о методе сказуемого:

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

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

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

каковы ваши мысли? У кого-нибудь из вас возникли проблемы с любым из вышеперечисленных методов? Есть рекомендации?

собирается начать новый проект, поэтому эти типы соображений имеют решающее значение.

Спасибо за помощь.

редактировать для уточнения по шаблону спецификации

здесь такое же использование картины спецификации.

Specification<Foo> someSpec; // Specification is an abstract class, implementing ISpecification<TEntity> members (And, Or, Not, IsSatisfiedBy).
someSpec = new AllFoosMustHaveABarSpecification(); // Simple class which inherits from Specification<Foo> class, overriding abstract method "IsSatisfiedBy" - which provides the actual business logic.    
ICollection<Foo> foos = fooDataService.GetFoosBySpecification(someSpec);

2 ответов


из моего небольшого опыта:

  1. требование пользователя всегда меняется, и я не знаю, почему мой босс всегда позволяет, чтобы изменения пришли. Так +1 к спецификации
  2. программист здесь больше похож на "ручного рабочего", чем на"работника умственного труда". Вы знаете.. тот, кто печатает целыми днями. Используя спецификацию, я могу убедиться, что все "типы". Это подтверждается характером моего проекта. Для одной и той же цели требуется много-много различных реализаций. Не спрашивай я почему.
  3. используйте шаблон проектирования, который дает вам высокую модульность и гибкость и, конечно, тестируемость. Вот небольшая история.мы в то время не заботились о модульном тестировании, поэтому мы использовали свой шедевр. Что случилось потом? Код все время ломался. Ну, с этого времени я понял, насколько важны модульный тест и модульность.

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

private ICollection<Foo> GetFoosBySpecification(Specification<Foo> spec) 
{ 
    return GetFooByPredicate(f => spec.IsSatisfiedBy(f));
} 

функция аргумента поиска будет аналогичной однострочной.

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