Contents
This article series will explore practical uses and applications of design patterns in day to day development practices, using practical examples in C#. The first article (one of hopefully many more to come) will cover the Decorator Pattern. This series is also published on my Blog C# | B# | Stay# [^] which as its name implies celebrates the #-ness in all things!
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 the holy grail of OO software developers (a slightly conceited statement perhaps) is to identify 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 be 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()));
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 that 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()
{
return new ContracteesQuery(new EmployeeQuery());
return new AgeLimitQuery(new ManagersQuery(new EmployeeQuery()), 50);
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#!
Here is a sample VS 2008 SP1 project that contains the query wrapper example. It is a console application that executes a sample query from the EmployeeQueryFactory
.
- 27 June 2010 - First version submitted
- 28 June 2010 - Added source code example