Wednesday, June 23, 2010

Design Patterns Part I :: Composed LINQ queries using the Decorator Pattern

This Blogs series will explore practical uses and applications of design patterns in day to day development practices, using practical examples in C#. The first Blog (one of hopefully many more to come) will cover the Decorator Pattern.

Introduction and Concepts

Let’s kick off this post with some theory. According to the GoF, the intent of the decorator design pattern is to
“Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality”
That was quoted from their seminal work Design Patterns: Elements of Reusable Object-Oriented Software

In my humble opinion, one of the greatest pleasures working in software development is when we can successfully implement a pattern, not through a premeditated intent but through natural and organic development of the code at hand. We spot the variation and try to encapsulate it and then lo and behold we end up using one pattern or another fulfilling its intent and purpose. I think a the holy grail of OO software developers (a slightly conceited statement perhaps) is to identify the what is common and what varies in any given requirement and then find a way to encapsulate that change making future (and almost inevitable requirement changes) relatively easy to implement.

After that brief techno-rant. We can go back to our main topic. The Decorator Design Pattern. Conceptually, here is how the pattern looks like:


The decorator pattern allows me to create a chain of objects (trail of decorator objects) namely, the decorators that are responsible for the new functionality, and ends with the original object. And the call chain looks like:



This is not to be confused with a linked list. Rather it should be regarded as a collection of optional decorating objects.

One classic example of this pattern is the stream I/O library. For any particular stream there is only one input, but there can zero or more actions to perform on the input stream. For instance, as in the example below, I can read from a memory stream, filter the stream and then read it using a custom stream reader. All these components (the later two are custom objects) implement the stream abstract class and accept a stream object in their constructors. the chain of calls looks like this:


Stream filteredMemoryStream =
                new StreamReader(new StreamFilter(new MemoryStream()));

Query Decorators


Personally, I use the decorator pattern to solve the problem of decomposing LINQ queries into more granular and reusable parts. A client can call several LINQ queries that are similar but only have minor variations. The direct result of this is LINQ code duplicated in every query. Another side effect is the tight coupling between the calling client and query composition.

The fictitious example I use here assumes we're querying an Employees repository and there are multitude of queries that might contain the same expressions and clauses. Say, we need to get all employees who are managers. Another requirement is what we get all employees who are managers and of certain age. We may then need to get the top %20 of those managers. All these extra queries are transformed into reusable decorators as follows:



As a direct result of this design, the query composition can be chained inside a factory that instantiates the desired query based on simple conditional logic of perhaps some configuration file:


public class EmployeeQueryFactory
{
    public static QueryComponent<Employee> GetQuery()
    {
        /*
         * We decouple the calling client from the query component instantiation
         * by using this factory method where we encapsulate all conditional
         * logic that determines which query component to instantiate
         * */

        //Get all employees who are contractees
        return new ContracteesQuery(new EmployeeQuery());

        //Get all managers older than 50
        return new AgeLimitQuery(new ManagersQuery(new EmployeeQuery()), 50);

        //Get top %20 of all contractees older than 30
        return new Top20PercentQuery(new AgeLimitQuery(new ContracteesQuery(new EmployeeQuery()), 30));
    }
}


And just to add more clarity to the example at hand, I add a simple implementation of the QueryComponent and QueryWrapper respectively, along with a concrete implementation of each.

public abstract class QueryComponent<T>
{
    public abstract IQueryable<T> Query();
}


public class EmployeeQuery : QueryComponent<Employee>
{
    public override IQueryable<Employee> Query()
    {
        return new EmployeesRepository().GetAllEmployess().AsQueryable();
    }
}


public abstract class QueryWrapper<T> : QueryComponent<T>
{
    protected readonly QueryComponent<T> QueryComponent;

    protected QueryWrapper(QueryComponent<T> queryComponent)
    {
        QueryComponent = queryComponent;
    }


    protected IQueryable<T> CallTrailer()
    {
        return null != QueryComponent ? QueryComponent.Query() : null;
    }
}


public class ContracteesQuery : QueryWrapper<Employee>
{
    public ContracteesQuery(QueryComponent<Employee> queryComponent)
        : base(queryComponent)
    {
    }


    public override IQueryable<Employee> Query()
    {
        return CallTrailer().Where(p => p.IsContractee);
    }
}

Lastly, as with every post. I leave you with this quote by Christopher Alexander
"We are searching for some kind of harmony between two intangibles: a form which we have not yet designed and a context which we cannot properly describe."

Code well and Stay#!

No comments:

Post a Comment