Skip to content

Specification Pattern: Flexible Business Rules

Specification Pattern: Flexible Business Rules

The Specification Pattern is a behavioral design pattern that allows you to encapsulate complex business logic into small, reusable, and testable objects called “Specifications.”

🏗️ The Problem

Suppose you have a system for filtering Products. You need to find products that are:

  • “In Stock”
  • “Above $100”
  • “From a specific Brand”
  • “On Sale”

If you build one large Search method, it becomes a mess of if-else and switch statements. Adding a new filter requires changing the search method.

🚀 The .NET Implementation

The Specification pattern is perfect for building flexible search/filter engines.

1. The Base Specification (Generic)

public interface ISpecification<T>
{
    bool IsSatisfiedBy(T entity);
}

2. Concrete Specifications

public class InStockSpecification : ISpecification<Product>
{
    public bool IsSatisfiedBy(Product p) => p.Quantity > 0;
}

public class HighValueSpecification : ISpecification<Product>
{
    public bool IsSatisfiedBy(Product p) => p.Price > 1000m;
}

3. Combining Specifications (AND logic)

public class AndSpecification<T> : ISpecification<T>
{
    private readonly ISpecification<T> _left;
    private readonly ISpecification<T> _right;

    public AndSpecification(ISpecification<T> left, ISpecification<T> right)
    {
        _left = left;
        _right = right;
    }

    public bool IsSatisfiedBy(T entity) => _left.IsSatisfiedBy(entity) && _right.IsSatisfiedBy(entity);
}

🛠️ Real-World Usage (Client)

var inStock = new InStockSpecification();
var highValue = new HighValueSpecification();

// Combine them dynamically!
var filter = new AndSpecification<Product>(inStock, highValue);

var result = _context.Products.Where(p => filter.IsSatisfiedBy(p)).ToList();

💡 Why use Specification?

  • SRP (Single Responsibility): Each business rule is in its own class.
  • OCP (Open/Closed Principle): You can add new filters without changing existing code.
  • Reusability: The InStockSpecification can be reused across the entire application.
  • Testability: Each specification can be unit tested in isolation.