Chapter One - Design Patterns - Lesson 1
Structural Patterns And Decorator Pattern
Structural Patterns
In this lesson, I'm going to write about the first of the three design pattern groups - the structural patterns.
As I wrote in my first post about design patterns, the structural patterns deal with composition of classes and objects and enable us to form larger structures.
The structural patterns include: Adapter, Bridge, Composite, Decorator, Facade, Flyweight and Proxy.
The advantage of using these patterns is that you can apply them while you are designing your project, or later on when you deploy or in the faze of maintenance.
Decorator Pattern
I'm going to start with the decorator pattern because I'm using it a lot these days and it is a common pattern.
The decorator pattern or wrapper (depends on your project architect) is providing a way to add functionality or new state to an implemented object without touching that object.
The decorator has two types of relations with the object it decorates.
The decorator is an object of the type it decorates therefore it can be used in the places that the original decorated object was used.
The decorator has an object of the type it decorates (one or more instance of that type) inside of it therefore it can use the functionality of that object.
For a UML diagram of the pattern go to dofactory site.
In the .Net framework there are a lot of wrappers and you can find some examples in the System.IO namespace.
Can you guess which classes are decorators? A tip - look at the Stream class and StreamWriter and StreamReader classes for example.
Decorator C# Example
Lets look at a little decorator example :
We have two players in the example - the Cop class and the Detective class.
The Cop class is the decorated class and the detective class is the decorator.
The Cop class:
public class Cop
{
#region Members
private string _Name;
#endregion
#region Properties
public string Name
{
get
{
return _Name;
}
set
{
_Name = value;
}
}
#endregion
#region Ctor
public Cop(string name)
{
Name = name;
}
#endregion
#region Methods
public virtual void arrestSuspect()
{
Console.WriteLine("Arrest suspect");
}
public virtual void detainSuspect()
{
Console.WriteLine("Detain suspect");
}
#endregion
}
As you can see there is nothing interesting about the Cop class. It has a Name property and two methods detainSuspect and arrestSuspect.
Now lets look on the Detective class:
public class Detective : Cop
{
#region Members
private Cop _cop;
#endregion
#region Ctor
public Detective(Cop cop)
{
_cop = cop;
}
#endregion
#region Methods
public void investigateSuspect()
{
Console.WriteLine("{0} Investigates the Suspect", Name);
}
public override void detainSuspect()
{
Console.WriteLine("Detain suspect and investigate");
}
#endregion
}
The Detective class wraps the Cop class by having a Cop member inside and therefore can use it's functionality.
Also, the Detective class inherits from the Cop class and therefore we can use it whenever we can use the Cop class.
You can see that the Detective class adds functionality that wasn't present in the Cop class - investigateSuspect method.
Summary
To sum up the post, the decorator pattern is useful and is implemented widely in .Net framework mainly in System.IO.
In my current project we use the decorator pattern to wrap legacy objects and to add them new functionality.
In the next post I'll continue the tour in the design patterns world and the structural patterns.