.NET and me Coding dreams since 1998!

24Oct/071

Flavors of decorator pattern

GOF Decorator

 Armen Ayvazyan has a great blog post Decorator pattern where in great details explains the purpose and logic behind the GoF decorator pattern.

At the end of his example he uses the next static class diagram

Summarized: the Car is abstract class which is inherited by Toyota and Honda child specialized car classes and a Decorator abstract child class. Decorator class contains a field member of a Car type, which value is been injected through dependency injection (constructor type) and then use implementation over delegation to delegate its implementation of Car abstract methods to the injected instance stored in decorator field

Problem

There is no problem as long as inheritance relationship between the Decorator and Car is acceptable. But if we would like to inherit Decorator from some class different then the Car or we wouldn't like to decorate complete car we would have to do some variations in the decorator GoF implementation.

Generic Decorator

Generic decorator is based upon the inheritance implementation through the usage of Generics.

image

We would modify Decorator class to become an generic one and remove the inheritance from the Car class so it would look like this:

   1: public abstract class Decorator<TCar> where TCar:Car, new()
   2: {
   3:     private readonly TCar _car=new TCar();
   4:  
   5:     /// <summary>
   6:     /// Start the decorated car engine.
   7:     /// </summary>
   8:     public void Start()
   9:     {
  10:         _car.Start();
  11:     }
  12:  
  13:     /// <summary>
  14:     /// Drive the decorated car engine.
  15:     /// </summary>
  16:     public void Drive()
  17:     {
  18:         _car.Drive();
  19:     }
  20:  
  21: }

The modification on Decorator child/specialized classes would look like

   1: /// <summary>
   2: /// Decorates a car to be a taxi.
   3: /// </summary>
   4: public sealed class TaxiCar<TCar> : Decorator<TCar> where TCar : Car, new()
   5: {
   6:  
   7:     private int _passengers;
   8:     /// <summary>
   9:     /// Number of passengers per single day.
  10:     /// </summary>
  11:     public int Passengers
  12:     {
  13:         get { return _passengers; }
  14:         set { _passengers = value; }
  15:     }
  16: }

Notice that with generics we don't need any more to implement constructor based dependency injection of an Car instance

So the usage of the new decorated class would look like

   1: static void Main(string[] args)
   2: {
   3:     TaxiCar<Toyota> rc = new TaxiCar<Toyota>();
   4:     rc.Passengers = 3;
   5:     rc.Start();
   6:     rc.Drive();
   7:     
   8:     Console.ReadLine();
   9: }

Summarized: Courtesy of generics we can get the benefits of the decorator patterns without having inheritance limitations . Our taxi car is decorating the car without inheriting from it.

Interface based Decorator

That GoF implementation can be slightly  altered in case the base class implements some interface and we would like to decorate just behavior contracted with that interface but not the whole class. One more reason why we would like to do that is maybe because of the need that we would like our Decorator class to inherit from some class other then car, so the base decorator class could be enriched with the certain car attributes. This is the way to get the effect of multiple inheritance in C# I described  in my implementation over delegation post.

If we slightly alter the solution Armen explained by introducing the ICar interface , we would se that the solution he has would compile without the single line of code changed (outside of interface definition and defining its implementation by Decorator and Car classes).

So, the  decouple decorator taking whole functionality of the base class case could look like this

 image

Another example of the same idea of interface based decorator is that car would implement (beside ICar) an IParkable interface with the AutoPark method. In implementing  the TaxiCar I would like to "steal" the IParkable behavior of the car and decorate my taxi with it without "decorating" the behavior defined with the ICar.

Something like this.

image

 

Summary

Decorator is very powerful pattern which can be used for supplementing the inheritance relationship with composition based relationship. The basic idea stated in GoF is very flexible and it can be implemented on several different ways

I presented here how it can be done through  Interfaces and  Generics, but I'm sure there are some other ways it can be done more.

Quote of the day:
If the facts don't fit the theory, change the facts. - Albert Einstein

Share this post :

Comments (1) Trackbacks (0)
  1. Your generics example of decorator pattern breaks the pattern intent.

    It works only for one level of decoration. What if you need to decorate TaxiCar<TCar> with some additional behavior?

    Your abstract decorator class takes the TCar as the generic parameter which is not same as TaxiCar.  Essentially you cannot chain the decorator classes, which is the intent of decorator pattern


Leave a comment

No trackbacks yet.