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

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

Классическая реализация паттерна проектирования выглядит следующим образом:

общедоступный интерфейс ISpecification
{
bool IsSatisfiedBy (объект-кандидат);
}

Что не так с C #?

1. Существуют Expression ‹Func‹ T, bool ›› и Func ‹T, bool ››. Их подписи совпадают

2. Есть методы расширения. Разработчики могут использовать их следующим образом:

открытый класс UserQueryExtensions
{
public static IQueryable ‹User› WhereGroupNameIs (это пользователи IQueryable ‹User›,
строковое имя)
{
return users.Where (u = ›U.GroupName == name);
}
}

3. Вы можете реализовать надстройку поверх LINQ:

public abstract class Specification ‹T›
{
public bool IsSatisfiedBy (T item)
{
return SatisfyingElementsFrom (new [] {item} .AsQueryable ()). Any () ;
}

общедоступная аннотация IQueryable ‹T› SatisfyingElementsFrom (кандидаты IQueryable ‹T›);
}

Наконец, у нас есть вопрос, стоит ли использовать шаблон Java 10-летней давности на C # и как мы можем его реализовать.

Мы решили, что надо его использовать. Итак, реализация паттерна теперь выглядит следующим образом:

открытый интерфейс IQueryableSpecification ‹T›
где T: class
{
IQueryable ‹T› Apply (запрос IQueryable ‹T›);
}

открытый интерфейс IQueryableOrderBy ‹T›
{
IOrderedQueryable ‹T› Apply (IQueryable ‹T› queryable);
}

public static bool Satisfy ‹T› (this T obj, Func ‹T, bool› spec) = ›spec (obj);

public static bool SatisfyExpresion ‹T› (this T obj, Expression ‹Func‹ T, bool ›› spec)
= ›spec.AsFunc () (obj);

public static bool IsSatisfiedBy ‹T› (this Func ‹T, bool› spec, T obj)
= ›spec (obj);

public static bool IsSatisfiedBy ‹T› (это выражение ‹Func‹ T, bool ›› spec, T obj)
= ›spec.AsFunc () (obj);

public static IQueryable ‹T› Где ‹T› (этот источник IQueryable ‹T›,
IQueryableSpecification ‹T› spec)
где T: class
= ›spec.Apply (источник);

Почему бы не использовать Func ‹T, bool›?

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

Если вы нашли эту заметку полезной, продолжайте читать в блоге - https://bit.ly/2wn3bZG.

Спасибо и следите за обновлениями!