2LeggedSpider

Getting specific with the Specification Pattern

Posted in C#, patterns by Sumit Thomas on March 23, 2011

The idea of Specification pattern according to Martin Fowler is to separate the statement of how to match a candidate, from the candidate object that it is matched against. As well as its usefulness in selection, it is also valuable for validation and for building to order.

In simple terms it means this pattern helps us to check if an object satisfies certain criteria. Well, we do that all the time in our code don’t we? For instance, we check if the data in an object that we send to a web service or database is properly validated against a business rule. We check for certain conditions on an object’s property to fetch subset of objects from a collection using say LINQ etc etc. Since we already do these things, why do we need a separate pattern to do the same?

Well the biggest advantage of Specification pattern is that we can create compartments of criteria definitions and check them against an object wherever the need arises. We then have the flexibility to change the criteria definitions in one single place as per the business requirement instead of changing it all the places where such criteria would had been used, if we didn’t use specification pattern. OK enough theory, lets see how we can implement the Specification pattern to understand it better.

We’ll start by creating the Core framework for the Specification. Lets create an Interface ISpecification with the following definition

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

Now as I mentioned earlier, we can check if an object satisfies a certain condition or a set of conditions. In order to make it easy for us we’ll create classes which will help us perform the logical And, Or and Not operations on an object with the available suggestions.

    public class AndSpecification<T> : ISpecification<T>
    {
        private readonly ISpecification<T> spec1;
        private readonly ISpecification<T> spec2;
        public AndSpecification(ISpecification<T> s1, ISpecification<T> s2)
        {
            spec1 = s1;
            spec2 = s2;
        }

        public bool IsSatisfiedBy(T t)
        {
            return spec1.IsSatisfiedBy(t) && spec2.IsSatisfiedBy(t);
        }

    }

    public class OrSpecification<T> : ISpecification<T>
    {
        private readonly ISpecification<T> spec1;
        private readonly ISpecification<T> spec2;
        public OrSpecification(ISpecification<T> s1, ISpecification<T> s2)
        {
            spec1 = s1;
            spec2 = s2;
        }

        public bool IsSatisfiedBy(T t)
        {
            return spec1.IsSatisfiedBy(t) || spec2.IsSatisfiedBy(t);
        }
    }

    public class NotSpecification<T> : ISpecification<T>
    {
        private readonly ISpecification<T> spec;
        public NotSpecification(ISpecification<T> spec)
        {
            this.spec = spec;
        }

        public bool IsSatisfiedBy(T t)
        {
            return !spec.IsSatisfiedBy(t);
        }
    }

Next we will create extension methods that will help us to chain together required specifications.

    public static class SpecExtensions
    {
        public static ISpecification<T> And<T>(this ISpecification<T> s1, ISpecification<T> s2)
        {
            return new AndSpecification<T>(s1, s2);
        }
        public static ISpecification<T> Or<T>(this ISpecification<T> s1, ISpecification<T> s2)
        {
            return new OrSpecification<T>(s1, s2);
        }
        public static ISpecification<T> Not<T>(this ISpecification<T> s)
        {
            return new NotSpecification<T>(s);
        }
    }

That pretty much forms the core implementation of Specification pattern. Now lets get in to the fun part where we will put the specification pattern in use.

Lets assume that you are creating a module for fictional employee management application to determine the qualification of employees in order to promote them to managers. Lets start by creating a Employee class as follows

    public class Employee
    {
        public int EmployeeId { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public int TotalExperience { get; set; }
        public ExcelCompetency ExcelCompetency { get; set; }
        public bool PotentialManager
        {
            get
            {
                if (ExcelCompetency == Domain.ExcelCompetency.High || ExcelCompetency == Domain.ExcelCompetency.Medium)
                    return true;

                return false;
            }
        }
    }

Here ExcelCompetency is an enum with values High, Medium and Low. Assume that the specification provided to you is that only Employees with High or Medium competency in Excel can become Managers. The property PotentialManager checks this condition and returns a boolean based on the value assigned for ExcelCompetency.

Though the property PotentialManager would help us in fetching a subset of employees qualified to be a manager from a list of employees, the actual condition we used inside this property might be used elsewhere in our application. In such cases, if the company decides later that employees with only High ExcelCompetency can become managers then we would have to change the condition wherever it is implemented. That is not ideal. This is where Specification pattern could be used.

Lets start by creating our own implementation of Specification framework.

    public class PotentialManagerSpecification : ISpecification<Employee>
    {
        public bool IsSatisfiedBy(Employee employee)
        {
            if (employee.ExcelCompetency == ExcelCompetency.High || employee.ExcelCompetency == ExcelCompetency.Medium)
                return true;
            return false;
        }
    }

Now our PotentialManager property could be changed to…

        public bool PotentialManager
        {
            get
            {
                var  potentialManagerSpec = new PotentialManagerSpecification();
                if (potentialManagerSpec.IsSatisfiedBy(this))
                    return true;
                return false;
            }
        }

Now the condition for satisfying a requirement will lie independent of the entity object and can be changed anytime without touching the entity.

Now lets assume that the management has laid down a condition that managers should not only have High Excel competency but also should have more than 10 years of experience. To satisfy this condition lets create another specification ManagerRequiredExperienceSpecification

    public class ManagerRequiredExperienceSpecification : ISpecification<Employee>
    {
        public bool IsSatisfiedBy(Employee employee)
        {
            if (employee.TotalExperience > 10)
                return true;
            return false;
        }
    }

We’ll create a test method to test these specifications

[TestMethod]
public void ManagerSelection_Test()
{
Employee abc = new Employee(){ FirstName="ABC", ExcelCompetency = ExcelCompetency.Medium, TotalExperience = 12};
Employee def = new Employee(){ FirstName = "DEF", ExcelCompetency = ExcelCompetency.High, TotalExperience = 11};
Employee qrs = new Employee(){ FirstName = "QRS", ExcelCompetency = ExcelCompetency.High, TotalExperience = 8};
Employee xyz = new Employee(){FirstName = "XYZ", ExcelCompetency = ExcelCompetency.Low, TotalExperience = 10};

IList employees = new List()
{
  abc, def, qrs, xyz
};

PotentialManagerSpecification managerSpec = new PotentialManagerSpecification();
ManagerRequiredExperienceSpecification experienceSpec = new ManagerRequiredExperienceSpecification();

foreach(Employee e in employees){
    System.Diagnostics.Debug.WriteLine(
      "{0} is {1} to be a Manager",
       e.FirstName,
       managerSpec.And(experienceSpec).IsSatisfiedBy(e) ? "qualified" : "not qualified"
       );
}
}

If you run the above test, your Debug trace will show the following output

ABC is qualified to be a Manager
DEF is qualified to be a Manager
QRS is not qualified to be a Manager
XYZ is not qualified to be a Manager

You can see in the line managerSpec.And(experienceSpec).IsSatisfiedBy(e) how we have used the extension method ‘And’.

Based on the requirement we can use the extension methods as follows.

  • managerSpec.And(experienceSpec).IsSatisfiedBy(e) -> Employee satisfies both PotentialManagerSpecification and ManagerRequiredExperienceSpecification
  • managerSpec.Or(experienceSpec).IsSatisfiedBy(e) -> Employee satisfies either PotentialManagerSpecification or ManagerRequiredExperienceSpecification
  • managerSpec.And(experienceSpec.Not()).IsSatisfiedBy(e) -> Employee satisfies PotentialManagerSpecification but not ManagerRequiredExperienceSpecification

As you can see the possibilities are limitless. If you want to create a new specification which handles both PotentialManagerSpecification and ManagerRequiredExperienceSpecification then we can also do so as follows

    public class ManagerSelectionSpecification : ISpecification<Employee>
    {
        public bool IsSatisfiedBy(Employee employee)
        {
            PotentialManagerSpecification managerSpec = new PotentialManagerSpecification();
            ManagerRequiredExperienceSpecification experienceSpec = new ManagerRequiredExperienceSpecification();

            if (managerSpec.And(experienceSpec).IsSatisfiedBy(employee))
                return true;

            return false;
        }
    }

We can also use specifications to perform validation before saving information in database for instance

var managerSelectionSpec = new ManagerSelectionSpecification();
if(managerSelectionSpec.IsSatisfiedBy(employee)
{
      PromoteToManager();
}

Or in LINQ as follows

 var managers = from e in employees
                           where managerSelectionSpec.IsSatisfiedBy(e)
                           select e;

Pretty neat isn’t it? I hope you found it useful as I did.

Some useful links…

Specifications by by Eric Evans and Martin Fowler

Repository, Specification, Unit of Work, Persistence Ignorance POCO with Microsoft ADO.NET Entity Framework 4.0 Beta 2

Learning the Specification Pattern

About these ads

11 Responses

Subscribe to comments with RSS.

  1. DotNetShoutout said, on March 23, 2011 at 11:36 pm

    Getting specific with the Specification Pattern…

    Thank you for submitting this cool story – Trackback from DotNetShoutout…

  2. [...] Getting specific with the Specification Pattern – Sumit Thomas takes a look at the implementation and testing of the specification pattern, a pattern designed for testing candidate objects for matches against a set of requirements. [...]

  3. Palle said, on March 24, 2011 at 3:06 pm

    You could make ISpecification an abstract base class with an abstract method IsSatisfiedBy(), and the methods And() Or() & Not(), instead of them being extension methods.
    Does this approach have any disadvantages over the one you describe?

    • Sumit Thomas said, on March 24, 2011 at 3:41 pm

      @Palle – I don’t think there is any disadvantage with the approach you have described and it should work perfectly fine. I used the extension method because I felt it is a simplified approach.

      Using an abstract class would have an added advantage as you can include additional utility methods that your derived Specifications can access

  4. James said, on March 24, 2011 at 10:02 pm

    Hi there,

    Aren’t you missing a whole heap of generics in your sample code??
    Cut and paste your ISpecification interface into VS and it won’t compile!!
    Shouldn’t it be ISpecification??
    In which case all the other code is broken too!

    Cheers,

    James

    • Sumit Thomas said, on March 24, 2011 at 10:58 pm

      James – thanks for pointing it out. I guess there was some problem while saving the content. I’ve corrected it.

  5. James Driscoll said, on March 24, 2011 at 11:10 pm

    Aha… I see that my <T> was gobbled up in my previous comment…
    And I guess the same happened with your post!

    Thanks for updating it… makes a huge amount more sense now!!!

    Cheers,

    James

  6. Anupama said, on March 25, 2011 at 7:49 pm

    cool :)

  7. Perry said, on March 28, 2011 at 9:04 pm

    I copied the SpecExtensions class and it won’t recognize “T”.

    • Sumit Thomas said, on March 28, 2011 at 9:25 pm

      Perry – the <T> after the method names And, Or and Not was gobbled up for some reason. Please take the updated code for SpecExtensions above.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: