specification pattern in csharp

Specification Pattern is a behavioral pattern that allows to specify business logic of an object in a declarative way.

Here is an example of how to implement specification pattern in C#:

main.cs
public abstract class Specification<T>
{
    public abstract bool IsSatisfiedBy(T entity);

    public Specification<T> And(Specification<T> specification)
    {
        return new AndSpecification<T>(this, specification);
    }
    public Specification<T> Or(Specification<T> specification)
    {
        return new OrSpecification<T>(this, specification);
    }
    public Specification<T> Not()
    {
        return new NotSpecification<T>(this);
    }
}

public class AndSpecification<T> : Specification<T>
{
    private readonly Specification<T> _spec1;
    private readonly Specification<T> _spec2;

    public AndSpecification(Specification<T> spec1, Specification<T> spec2)
    {
        _spec1 = spec1;
        _spec2 = spec2;
    }

    public override bool IsSatisfiedBy(T entity)
    {
        return _spec1.IsSatisfiedBy(entity) && _spec2.IsSatisfiedBy(entity);
    }
}

public class OrSpecification<T> : Specification<T>
{
    private readonly Specification<T> _spec1;
    private readonly Specification<T> _spec2;

    public OrSpecification(Specification<T> spec1, Specification<T> spec2)
    {
        _spec1 = spec1;
        _spec2 = spec2;
    }

    public override bool IsSatisfiedBy(T entity)
    {
        return _spec1.IsSatisfiedBy(entity) || _spec2.IsSatisfiedBy(entity);
    }
}

public class NotSpecification<T> : Specification<T>
{
    private readonly Specification<T> _spec;

    public NotSpecification(Specification<T> spec)
    {
        _spec = spec;
    }

    public override bool IsSatisfiedBy(T entity)
    {
        return !_spec.IsSatisfiedBy(entity);
    }
}

public class Customer
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
}

public class CustomerAgeSpecification : Specification<Customer>
{
    private readonly int _age;

    public CustomerAgeSpecification(int age)
    {
        _age = age;
    }

    public override bool IsSatisfiedBy(Customer entity)
    {
        return entity.Age == _age;
    }
}

public class CustomerNameSpecification : Specification<Customer>
{
    private readonly string _name;

    public CustomerNameSpecification(string name)
    {
        _name = name;
    }

    public override bool IsSatisfiedBy(Customer entity)
    {
        return entity.Name == _name;
    }
}
2308 chars
104 lines

Here is example usage of the above code:

main.cs
var customer = new Customer { Id = 1, Age = 30, Name = "John" };
var ageSpec = new CustomerAgeSpecification(30);
var nameSpec = new CustomerNameSpecification("John");

// Let's combine the specs
var ageAndNameSpec = ageSpec.And(nameSpec);
var ageOrNameSpec = ageSpec.Or(nameSpec);

// Let's test the specs
var isAgeAndNameSatisfied = ageAndNameSpec.IsSatisfiedBy(customer); // true
var isAgeOrNameSatisfied = ageOrNameSpec.IsSatisfiedBy(customer); // true
456 chars
12 lines

related categories

gistlibby LogSnag