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
InStockSpecificationcan be reused across the entire application. - Testability: Each specification can be unit tested in isolation.