Specification Pattern Continued

In a previous post, I talked about the specification pattern. In the last sentence I promised you to keep you posted on the next version of the implementation. I still owe you guys that result. So without further ado:

Download it here.

The implementation itself is pretty straightforward. The class has a protected property Predicate that takes in a Lambda expression that results in a boolean ( a predicate). It is protected so that you have to set the predicate in the derived class.

/// <summary>
/// Use the Specification to make some complex (business) logic explicit.
/// </summary>
/// <typeparam name="TEntity">The Type of entity that is the subject of the specification</typeparam>
public abstract class Specification<TEntity>
{

protected Func<TEntity, bool> evalCompiled;
protected Expression<Func<TEntity, bool>> evalExpression;

protected internal Expression<Func<TEntity, bool>> Predicate
{
get
{
return evalExpression;
}
set
{
evalExpression = value;
evalCompiled = evalExpression.Compile();
}
}

/// <summary>
/// Use this method to evaluate the predicate for a single item.
/// </summary>
/// <param name="item">The item to examine</param>
/// <returns>A boolean.</returns>
public bool IsSatisfiedBy(TEntity item)
{
return evalCompiled(item);
}

/// <summary>
/// Use this method to filter IQueryables using the Predicate
/// </summary>
/// <param name="candidates">The IQueryable that needs filtering</param>
/// <returns>An IQueryable that has the added filter</returns>
public IQueryable<TEntity> SatisfyingElementsFrom(IQueryable<TEntity> candidates)
{
return candidates.Where(evalExpression);
}
}

The usage is simple.

Suppose that there is a business rule that big orders need approval by a manager. Big orders are orders above a 1000 euros. There are 2 cases when we need to know whether an order is a big order. First, when the order is created so that we can send a request for approval to the manager and second in a managers app that shows all the big orders.

The class IsBigOrderSpecification is a business rule made explicit. This rule could be throughout your system. Here’s what it looks like:

class IsBigOrderSpecification : Specification<SalesOrderDetail>
{
public IsBigOrderSpecification()
{
Predicate = (o => o.LineTotal >= 1000);
}
}

When a new order is created we can now use this specification to enforce the business rule.

SalesOrderDetail orderLine = new SalesOrderDetail();
orderLine.LineTotal = 999;
bool isBigOrderLine = isBigOrderLineSpec.IsSatisfiedBy(orderLine);
if (isBigOrderLine)
{
Console.WriteLine("LineTotal {0} means this is a big orderline.", orderLine.LineTotal);
}
else
{
Console.WriteLine("LineTotal {0} means this is a not big orderline.", orderLine.LineTotal);
}

Yet the same specification can be used when querying for these big orders in the system. Because it works on IQueryable<SalesOrderDetail> we get all the advantages of deferred execution.

AdventureWorksEntities db = new AdventureWorksEntities();

var query = from so in db.SalesOrderDetails
select so;

var bigOrderLines = isBigOrderLineSpec.SatisfyingElementsFrom(query);

Console.WriteLine("{0} big OrderLines in database", bigOrderLines.Count());

 

Composite specification

In the solution you can also find the code to create composite specifications. Composite specifications are specifications that have been combined. What if we changed the business rule (the manager is getting to busy) to state that only big orders from sales people that have little experience have to be approved. Little experience has been qualified at working at the company less than 2 years. You probably get an IsExperiencedSalesPersonSpecification.

We are now able to combine the 2 specifications as follows:

bool needsApproval = isBigOrderLineSpec.And(new IsExperiencedSalesPersonSpecification().Not()).IsSatisfiedBy(orderLine);

 

My opinion is that this specification pattern is quite powerful in specifying and enforcing business rules in a distributed system.