The Decorator pattern is a means to transparently add responsibilities to another object on the fly. In some cases it’s a simpler solution than creating additional subclasses through inheritance. A decorator is implemented by creating a class that wraps access to another class. The decorator implements the exact same public interface as it’s inner member. That sounds like a lot of gobbledy-gook to me too, so let’s jump into a code sample.
I’ve frequently written code like the following to iterate through an IDataReader and read the data. There’s always a little bit of coercion on the raw data from the database when you move the data to .Net Types. Several database engines don’t have a true boolean type, so you use a coding convention like “0/1″ or “Y/N” as a standin for a boolean type. You may want to treat a null value in the database as either an empty string or 0. That results in a lot of code like this below:
public Somebody[] GetSomebodies()
{
ArrayList list = new ArrayList();using (IDataReader reader = this.fetchReader())
{
while (reader.Read())
{
string name = reader.GetString(0);
int age = reader.IsDBNull(1) ? 0 : reader.GetInt32(1);
string email = reader.IsDBNull(2) ? string.Empty : reader.GetString(2);
bool active = reader.GetString(3) == “Y” ? true : false;Somebody somebody = new Somebody(name, age, email, active);
list.Add(somebody);
}
}return (Somebody[]) list.ToArray(typeof (Somebody));
}
Over time this kind of coercion code builds up, and it’s all a bunch of duplicated code. It’s also irritating when you hit defects because you forgot to check for null values on a column. Not to mention that it makes the code harder to read because you’re getting tangled up in the casting. Wouldn’t be nice if the DataReader could be smart enough to do the type coercion and null substitution for us? We can’t very easily go and alter SqlClient or OracleClient to do this ourselves (they’re both sealed). One slick alternative I’ve seen is to use the Decorator pattern to create a new IDataReader class that wraps the underlying reader just to intercept the null values and substitute a default value. Here’s what the code might look like with the decorated reader.
public Somebody[] GetSomebodies()
{
ArrayList list = new ArrayList();using (IDataReader innerReader = this.fetchReader())
{
IDataReader reader = new DefaultedReader(innerReader);while (reader.Read())
{
string name = reader.GetString(0);
int age = reader.GetInt32(1);
string email = reader.GetString(2);
bool active = reader.GetBoolean(3);Somebody somebody = new Somebody(name, age, email, active);
list.Add(somebody);
}
}return (Somebody[]) list.ToArray(typeof (Somebody));
}
All I did is push a lot of the coercion code to the new decorator class. It’s not that big of deal, but it frees me to concentrate on the mapping rather than a bunch of defensive coding. A partial implementation of the DefaultedReader is below.
public class DefaultedReader : IDataReader
{
private readonly IDataReader _innerReader;public DefaultedReader(IDataReader innerReader)
{
_innerReader = innerReader;
}public void Close()
{
_innerReader.Close();
}// Straight Delegation
public bool Read()
{
return _innerReader.Read();
}// Substitute true/false for “Y”/”N”
public bool GetBoolean(int i)
{
string booleanString = _innerReader.GetString(i);
return booleanString == “Y” ? true : false;
}public string GetString(int i)
{
return _innerReader.IsDBNull(i) ? string.Empty : _innerReader.GetString(i);
}// Wrap the call to _innerReader.GetInt32()
public int GetInt32(int i)
{
return _innerReader.IsDBNull(i) ? 0 : _innerReader.GetInt32(i);
}// Rest of the IDataReader implementation
}
The mechanics are pretty simple. The DefaultedReader class implements the IDataReader interface, so it can be used any place that expects an IDataReader. DefaultedReader takes an IDataReader as its only constructor argument and keeps an internal reference to the “inner” reader. Most methods in the DefaultedReader will just delegate to the inner reader. I haven’t been paying attention enough to know if the new Nullable types eliminate the need for this trick, but I just wanted to demonstrate how a construct like this could be useful.
A lot of the elegance of the decorator pattern is the ability to add extra behavior to a class without creating subclasses. We’ve already decided that we can’t effectively make a subclass of SqlDataReader just to do the null value resolution. Using a decorator in a case like this eliminates the need to create lots of subclass’s. Our DefaultedReader class will work identically when it’s decorating a SqlDataReader as it will an OracleDataReader, OleDbDataReader, or OdbcDataReader.
Here’s another example. In my StructureMap code I have an interface called IInstanceFactory that is responsible for the assembly of a named object instance. The basic InstanceFactory class reads configuration and creates a new instance based on that configuration. Here’s part of that interface.
///
/// Interface for a “Factory” pattern class that creates object instances of the PluginType
///
public interface IInstanceFactory
{
///
/// Creates an object instance for the InstanceKey
///
/// The named instance
///
object GetInstance(string InstanceKey);///
/// Creates a new object instance of the default instance memento
///
///
object GetInstance();
}
Sometimes you aren’t going to want a brand new instance every time. You may want to share the same instance for every request. You might want to associate an instance with the executing thread or the current HttpContext. StructureMap has a simple mechanism to modify the creation of new object instances by wrapping one or more decorators around an InstanceFactory. The calling code in StructureMap only cares about the IInstanceFactory interface, so calling into the decorator(s) is transparent to the calling code. So far, the only thing I’ve used this for is to create pseudo-Singleton instances. The entire code for the decorator class is below.
///
/// The SingletonInterceptor is a GoF Decorator around an IInstanceFactory that ensures that
/// only one instance is created for a given InstanceKey as a more testable alternative to
/// the GoF Singleton pattern.
///
[Pluggable(“Singleton”)]
public class SingletonInterceptor : InstanceFactoryInterceptor
{
private Hashtable _instances;public SingletonInterceptor() : base()
{
_instances = new Hashtable();
}public override object GetInstance(string instanceKey)
{
ensureInstanceIsCached(instanceKey);return _instances[instanceKey];
}private void ensureInstanceIsCached(string instanceKey)
{
if (!_instances.ContainsKey(instanceKey))
{
lock (this)
{
if (!_instances.ContainsKey(instanceKey))
{
// Delegate to teh inner InstanceFactory to construct a new instance
object instance = this.InnerInstanceFactory.GetInstance(instanceKey);
_instances.Add(instanceKey, instance);
}
}
}
}public override object GetInstance()
{
return this.GetInstance(this.DefaultInstanceKey);
}
}
Most of the work is still delegated to the inner IInstanceFactory. Some of the other possibilities would be adding caching or object pooling, providing an opportunity to attach a decorator to the new instance, or substituting a mock object or a stub during testing (this has turned out to be pretty effective in some cases).
Examples in the .Net Framework
One of the reasons I think design patterns are important is that they occur in other people’s code we inherit and use. Recognizing the patterns in someone else’s code can help you understand that code. Here’s a handful of examples from the
- Chaining IHttpModule classes in an ASP.NET application is an example of a decorator. Each IHttpModule in the interception chain adds behavior before it delegates to it’s inner IHttpModule. Microsoft refers to this specific usage or a decorator as an Intercepting Filter.
- The XmlValidatingReader class adds schema validation to any type of XmlReader. Clients that depend on the XmlReader type never know the difference.
- The System.IO.BufferedStream decorates any other kind of Stream to add buffering. By using a decorator pattern, the .Net team didn’t need to create specific subclasses for “BufferedFileStream” or “BufferedMemoryStream.” There is another Stream class that decorates other streams to provide transparent encryption.
Wrapping Up
The decorator pattern can help decompose optional or extra behavior into a separate class. Any chance you get to eliminate structured logic “if/then” constructs is a chance to improve the readability and maintainability of the code. The decorator also gives you a relatively low risk way to extend a system with new behavior like security, caching, or extra instrumentation at configuration time via the Open/Closed Principle.
If this was useful, or I could have done something better to explain the pattern, let me know. I’ll try to do a couple more of these posts over the next month.