Tim McCarthy's Blog

Stuff I think about...

My Links

Blog Stats

News

Archives

Post Categories

Image Galleries

A Composite Specification Pattern Implementation in .NET 2.0

.NET 2.0 Composite Specification Pattern Implementation

 

According to Fowler and Evans, the idea of using Specifications is to separate the statement of how to match a candidate, from the candidate object that it is matched against.  The main motivation pattern is to be able to select a list of objects from another list using various criteria in a very flexible, robust way.  A nice side benefit of using Specifications is that they can be used for object validation/constraints as well as for building objects to order (like in a Factory).  I was first introduced to this pattern from reading Eric Evans’ excellent book, Domain-Driven Design.

 

I have implemented the Specification pattern using the Composite pattern in order to provide the ability to combine Specifications in various ways.  I really needed this in a project, and I was surprised that I could not find any .NET implementations out in the blogoshpere, so I went ahead and wrote my own, with a little help from Reflection and Generics.

 

Here is the basic diagram of the top-level classes:

 

LeafNodesClassDiagram

 

For the AndSpecification and OrSpecification classes, they both take two ISpecification instances in their constructors, which represent the classes to be AND’ed or OR’ed together.

 

Here is a diagram of the Leaf-node classes of the Composite:

 

LeafNodesClassDiagram

 

As you can see in this diagram, every Leaf is actually a Composite, which makes it very easy to combine Specifications.  Below is a code example of how to combine specifications and use them:

 

 ///

///A test for IsSatisfiedBy (TCandidate)

///

[TestMethod()]

public void CustomerIsSatisfiedByEqualAndStartsWithTest()

{

    TestCustomer candidate = new TestCustomer();

    candidate.FirstName = "Tim";

    candidate.LastName = "McCarthy";

           

    bool expected = true;

    bool actual = new EqualSpecification<TestCustomer,

        string>("FirstName",

        "Tim").And(new StartsWithSpecification<TestCustomer,

        string>("LastName", "M")).IsSatisfiedBy(candidate);

 

    Assert.AreEqual(expected, actual,

                "The CompositeSpecification did not return the expected value.");

}

 

In this example, an EqualSpecification is combined with a StartsWithSpecification to perform two tests on the candidate object, which happens to be a TestCustomer type.  The first test specifies that the FirstName property of the TestCustomer instance (the candidate) is equal to “Tim”.  The second test specifies that the LastName property of the TestCustomer instance (the candidate) starts with the character “M”.  The power of this is that the tests by themselves are very granular and easy to understand, yet also very easy to combine and execute, as evidenced by how the code sample combined two specifications on one line of code.

 

The code for the implementation (as well as a sample application) can be found here.  Enjoy!

 

[5/22/2007:  I moved the code for this project over to CodePlex.  It can now be accessed here:  http://www.codeplex.com/spec]

 

I definitely welcome any feedback on this code as well.

posted on Monday, January 22, 2007 4:15 PM