Giter VIP home page Giter VIP logo

specification's Introduction

Logo

Coverage Status Build Status Nuget version Nuget stats

Паттерн Спецификация на .NET

Определение

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

Область применения

  1. Валидация объекта в памяти на соответствие требованиям
  2. Поиск объектов в базе данных, соответствующих требованиям
  3. Создание экземпляра объекта по требованиям - это невозможно, т.к. спецификация инкапсулирует требования внутри себя. случайный перебор всех вариантов - это плохой подход.

Возможности этой библиотеки

  1. Cтрого-типизированные спецификации
  2. Динамические спецификации
    • однострочные спецификации прямо в коде
  3. Запросы в Базу Данных, а также коллекции в памяти, через Linq
  4. Fluent-интерфейс
    • .And()
    • .Or()
    • .Not()
  5. Поддержка операторов
    • &
    • |
    • !
    • ==
    • !=
  6. Множество методов расширений для коллекций
    • .Is()
    • .IsAny()
    • .IsAll()
    • .AnyIs()
    • .AllIs()
  7. Реактивные экшен-методы для выполнения действия, при False результате
    • например можно подсчитать сколько объектов из коллекции не соответствуют спецификации
    • или выполнить какой-либо метод для объектов из коллекции, которые не соответствуют специцикации

Cтрого-типизированные спецификации

Базовый абстрактный класс, который необходимо наследовать и реализовать

public abstract class AbstractSpec<T> : ISpecification<T>
{
    public abstract Expression<Func<T, bool>> Expression { get; }
    public bool IsSatisfiedBy(T candidate)
    {
        // implementation
    }
}

Пример:

// Скучный фильм
public class BoringMovieSpec : AbstractSpec<Movie>
{
    private readonly TimeSpan _durationGreaterThat;
    private readonly double _ratingLessOrEqualThat;

    public BoringMovieSpec(TimeSpan? durationGreaterThat = null, double ratingLessOrEqualThat = 4)
    {
        _durationGreaterThat = durationGreaterThat ?? TimeSpan.FromHours(2.5);
        _ratingLessOrEqualThat = ratingLessOrEqualThat;
    }
    
    public override Expression<Func<Movie, bool>> Expression
        => movie => movie.Duration > _durationGreaterThat &&
                    movie.Rating <= _ratingLessOrEqualThat;
}

Динамические спецификации

AbstractSpec<Movie> spec = new Spec<Movie>(m => m.Rating > 5 && m.MpaaRating == MpaaRating.PG13);

Запросы в Базу Данных, а также коллекции в памяти, через Linq

using var db = new OrdersDbContext();

var richProductsSpec = new Spec<Order>(x => x.Products.Any(p => p.Price >= 500));

var query = db.Orders
    .Include(o => o.Products)
    .Where(richProductsSpec);

var orders = query.ToList();

Fluent-интерфейс

AbstractSpec<Movie> longest = new Spec<Movie>(m => m.Duration > TimeSpan.FromHours(2.5));
AbstractSpec<Movie> ratingLess = new Spec<Movie>(m => m.Rating <= 3);

var combineSpecs1 = longest.And(ratingLess);
var combineSpecs2 = longest.Or(ratingLess); 

Поддержка операторов

AbstractSpec<Movie> longest = new Spec<Movie>(m => m.Duration > TimeSpan.FromHours(2.5));
AbstractSpec<Movie> ratingLess = new Spec<Movie>(m => m.Rating <= 3);

var combineSpecs1 = longest & ratingLess;
var combineSpecs2 = longest | ratingLess;

Множество методов расширений для коллекций

Movie movie = new Movie()
{
    Rating = 3,
};

var spec1 = new Spec<Movie>(m => m.Rating == 2);
var spec2 = new Spec<Movie>(m => m.Rating == 3);
var spec3 = new Spec<Movie>(m => m.Rating == 4);

var result = movie.IsAny(spec1, spec2, spec3);
ICollection<Movie> movies = new List<Movie>
{
    new Movie { Rating = 2 },
    new Movie { Rating = 3 },
    new Movie { Rating = 4 },
    new Movie { Rating = 5 },
    new Movie { Rating = 6 },
};

var spec = new Spec<Movie>(m => m.Rating > 4);

var result = movies.AnyIs(spec);

Реактивные экшен-методы для выполнения действия, при False результате

OnFalseAction выполняется только при выполнении метода IsSatisfiedBy(), а значит только при вызове операторов: .Is(), .IsAny(), .IsAll(), .AnyIs(), .AllIs()

простой пример на проверку одного объекта:

 Movie movie = new Movie()
{
    Rating = 4,
    MpaaRating = MpaaRating.G
};

var spec = new Spec<Movie>(m => m.Rating > 5 && m.MpaaRating == MpaaRating.R);
var actionValue = false;
spec.OnFalseAction = (s, c) => actionValue = true;

var result = movie.Is(spec); // actionValue станет true, т.к. спецификация вернет False

сложный пример, проверка коллекции через методы расширения:

IEnumerable<Movie> movies = new List<Movie>
{
    new Movie { Rating = 2 },
    new Movie { Rating = 3 },
    new Movie { Rating = 4 },
    new Movie { Rating = 5 },
    new Movie { Rating = 6 },
};
var counter = 0;
var spec = new Spec<Movie>(m => m.Rating > 4)
{
    OnFalseAction = (spec, candidate) => counter++
};

var result1 = movies.AllIs(spec); // сработает для всех кто вернул false, в данном случае counter будет равен 3, т.к. всего 3 объекта не соответсвуют 
var result2 = movies.AnyIs(spec); // сработает для всех, если никто не вернул true, в данном случае counter будет равен 0 - т.к. в коллекции есть хотябы один объект попадающий под спецификацию

OnFalseAction не выполняется при запросах в БД или запросах в коллекции через Linq

Подключение библиотеки через Nuget

Install-Package Nymezide.Specification

Поддержка фрейморков

  • .NET Standard 2.1
  • .NET 5.0
  • .NET 6.0

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.