logo
  • Jobs
  • About Me
  • Contact
  • Home
« AJaX: The latest buzzword
The importance of CultureInfo »

The Specification Pattern: A Primer

Posted March 25th, 2005 by Matt Berther

The Specification pattern is a very powerful design pattern which can be used to remove a lot of cruft from a class’s interface while decreasing coupling and increasing extensibility. It’s primary use is to select a subset of objects based on some criteria, and to refresh the selection at various times.

For example, I’ve seen a lot of classes that have interfaces that look something similar to this:

public class User
{
    public string Company;
    public string Name;
    public string City;
}
 
public class UserProvider
{
    public User[] GetUserByName(string name)
    {
    }
 
    public User[] GetUsersByCity(string name)
    {
    }
 
    public User[] GetUsersByCompany(string company)
    {
    }
}

Using this model, you can see that every time you want to add a new condition for user retrieval, you have to add a method to the UserProvider class which obfuscates the interface.

Now, lets look at the same example using the specification pattern.

public class User
{
    public string Company;
    public string Name;
    public string City;
}
 
public class UserSpecification
{
    public virtual bool IsSatisfiedBy(User user)
    {
        return true;
    }
}
 
public class UserProvider
{
    public User[] GetBySpecification(UserSpecification spec)
    {
        ArrayList list = new ArrayList();
 
        UserCollection coll = SomeMethodToPopulateTheUserCollection();
        foreach (User user in coll)
        {
            if (spec.IsSatisfiedBy(user))
            {
                list.Add(user);
            }
        }
 
        return (User[])list.ToArray(typeof(User));
    }
}
 
class UserCompanySpecification : UserSpecification
{
    private readonly string companyName;
 
    public UserCompanySpecification(string companyName)
    {
        this.companyName = companyName;
    }
 
    public override bool IsSatisfiedBy(User user)
    {
        return user.Company.Equals(companyName);
    }
}

Using the specification pattern, we have removed all of the specialized methods from the UserProvider class. Also, because of the loose coupling, any time we want an additional condition for user retrieval, we need to only implement a new UserSpecification and pass this instance off to the GetBySpecification method, rather than polluting the existing interface.

This allows the calling code to determine exactly how it wants to filter any given collection, rather than the provider code assuming that it knows how the user wants it.

Of course, there is nothing preventing an API designer from putting a few commonly used specifications into the API itself.

This pattern is very powerful, but like anything can be overused. Make sure to review the consequences in the linked description of the pattern for when you should and shouldnt use this pattern.

This entry was posted on Friday, March 25th, 2005 at 2:45 pm and is filed under Uncategorized. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

Jeff Perrin - Sexier Than You Are : The Specification Pattern
December 13th, 2006

[...] So what the heck is it? Matt Berther provided a pretty good introduction where he states: It’s primary use is to select a subset of objects based on some criteria… [...]

Prasanna Krishnan
May 15th, 2008

Hi Matt,

The GetBySpecification can be refactored bit elegant with the following code.

public IEnumrable GetBySpecification(UserSpecification spec)
{

UserCollection coll = SomeMethodToPopulateTheUserCollection();
foreach (User user in coll)
{
if (spec.IsSatisfiedBy(user))
{
yeild return user;
}
}

– Prasanna

Matt Berther
May 16th, 2008

@prasanna: you’re correct. This looks much nicer. When I originally wrote this post, I was using .NET 1.1, which had no support for the yield keyword. Thanks for the update.

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>
-->

Social
  • mattberther on twitter
Syndication
Archives
  • August 2008
  • June 2008
  • May 2008
  • April 2008
  • March 2008
  • February 2008
  • January 2008
  • December 2007
  • November 2007
  • October 2007
  • September 2007
  • August 2007
  • July 2007
  • June 2007
  • May 2007
  • April 2007
  • March 2007
  • February 2007
  • January 2007
  • December 2006
  • November 2006
  • October 2006
  • September 2006
  • August 2006
  • July 2006
  • June 2006
  • May 2006
  • April 2006
  • March 2006
  • February 2006
  • January 2006
  • December 2005
  • November 2005
  • October 2005
  • September 2005
  • August 2005
  • July 2005
  • June 2005
  • May 2005
  • April 2005
  • March 2005
  • February 2005
  • January 2005
  • December 2004
  • November 2004
  • October 2004
  • September 2004
  • August 2004
  • July 2004
  • June 2004
  • May 2004
  • April 2004
  • March 2004
  • February 2004
  • January 2004
  • December 2003
  • November 2003
  • October 2003
  • September 2003
  • August 2003
  • July 2003
  • June 2003
  • May 2003
  • April 2003
  • March 2003
Jobs
mattberther.com © 2003 - 2008