The Specification Pattern and c# 3.5

by adrian.tosca 30. July 2008 13:37

The specification pattern popularized by Eric Evans and Martin Fowler can prove a powerful tool to make rules scattered all around the code explicit and part of the model. The specification pattern, in its simplest form is no more than Boolean test implemented in terms of objects.

Test methods like productStock.IsEmpty() are part of any application and as long as they are simple they can remain as Boolean tests. But tests often depend on complex object state. The tests can be combined to create even more complex rules. The rules are often scattered in every corner of the application and the same tests can appear in more than one place, making modifications difficult and error prone. In such cases it is often better to refactor the rules in classes and make the tests explicit specifications.

In the simple case of the productStock.IsEmpty() the initial code:

class ProductStock {
	public int ProductCount {
		get {
			return _productCount;
		}
	}

	public bool IsEmpty() {
		return ProductCount == 0;
	}
}

Can be refactored into:

class ProductStock {
	public int ProductCount {
		get {
			return _productCount;
		}
	}
}

class EmptyStockSpecification {
	bool IsSatisfiedBy(ProductStock candidate) {
		return candidate.ProductCount == 0;
	}
}

The new class EmptyStockSpecification is a "specification" that states a constraint on the state of another object. The simplest use of this new class is to test if an object satisfy the criteria. It doesn't look like a big improvement but the usefulness became apparent when the simple specifications can be combined to provide complex rules the same way the predicates are combined in logic expressions. The pattern remain simple but allow complex rules without a complex model. There are three main uses of specification pattern:

Validation - To see if an object fulfill some conditions or is ready for some use

if (emptyStockSpec.IsSatifiedBy(prodStock)) {
    ...
}

Selection - To select a subset of objects from a collection based on some criteria

foreach(ProductStock prodStock in allProdStocks) {
    if (emptyStockSpec.IsSatifiedBy(prodStock))
        results.Add(prodStock);
}

Generation - To allow creation of new objects that fulfill some need

ProductStockView view = new ProductStockView();
foreach(ProductStock prodStock in allProdStocks) {
    if (emptyStockSpec.IsSatifiedBy(prodStock))
        view.ProductStocks.Add(prodStock);
}

The three uses are the same on conceptual level. The selection is one of the most used pattern. In c# 2.0 there was possible to use the composite pattern to build complex specifications out of simple ones as can be seen in this very good presentation of the specification pattern. In c# 3.5 the possibility to use lambda expressions and LINQ to Entities for combining specifications makes the pattern much simpler to use.

For example,

struct ProductStock {
	public int ProductCount;
	public int MinLimit;
	public DateTime NextSupplyDate;
}

interface ISpecification
{
	bool IsSatisfiedBy(T candidate);
}

class CloseToMinLimitStockSpecification : ISpecification {
	decimal _variationPercent;
	public CloseToMinLimitStockSpecification(decimal variationPercent) {
		_variationPercent = variationPercent;
	}
	public bool IsSatisfiedBy(ProductStock candidate) {
		return candidate.ProductCount < 
			candidate.MinLimit * (1 + _variationPercent);
	}
}

defines the CloseToMinLimitStockSpecification specification that allows selection of product stocks that are close to the minimum stock limit. The new class can be used to select from a list of stocks the ones that are close to the minimum limit like this:

CloseToMinLimitStockSpecification closeToMinLimit =
	new CloseToMinLimitStockSpecification(0.1M);
IList stocksCloseToLimit =
	all.Where(p => closeToMinLimit.IsSatisfiedBy(p)).ToList();

The possibility to combine specifications in complex conditions is very powerful and simple to use. If another specification that allows selection of products stocks for which the supply date is not far away is defined like this,

class FarToSupplyDateStockSpecification : ISpecification {
	TimeSpan _span;
	public FarToSupplyDateStockSpecification(TimeSpan span) {
		_span = span;
	}
	public bool IsSatisfiedBy(ProductStock candidate) {
		return DateTime.Now.Add(_span) <= candidate.NextSupplyDate;
	}
}

the two specifications can be used to make a complex selection:

FarToSupplyDateStockSpecification farToSupplyDate =
	new FarToSupplyDateStockSpecification(new TimeSpan(60, 0, 0, 0));
IList stocksLikelyToGoUnderLimit =
	all.Where(p => closeToMinLimit.IsSatisfiedBy(p)
	&& farToSupplyDate.IsSatisfiedBy(p)).ToList();

However if it is necessary to combine specifications to make complex rule explicit classes, the composite pattern is to be used. The same classes can be even used with database objects but of course there are performance issues to consider in this case that require a more complex approach.

Download the complete example SpecificationPattern.zip (3.76 kb) containing the code listed above.

Tags:

Programming

Comments

Comments are closed

Powered by BlogEngine.NET 1.5.0.7
Theme by Mads Kristensen

RecentComments

Comment RSS

Calendar

<<  September 2010  >>
MoTuWeThFrSaSu
303112345
6789101112
13141516171819
20212223242526
27282930123
45678910

View posts in large calendar