В компьютерном программировании шаблон спецификации - это особый шаблон проектирования программного обеспечения, в соответствии с которым бизнес-правила могут быть рекомбинированы путем объединения бизнес-правил в цепочку с использованием логической логики. Шаблон часто используется в контексте проектирования, ориентированного на предметную область.
Короче говоря, основное преимущество использования «спецификаций» - это возможность иметь все правила для фильтрации объектов модели предметной области в одном месте вместо тысячи лямбда-выражений, разбросанных по приложению.
Классическая реализация паттерна проектирования выглядит следующим образом:
общедоступный интерфейс 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.
Спасибо и следите за обновлениями!