Combining the Decorator Pattern with the Template Method Pattern

Design patterns are exactly that, patterns of design. These patterns have been determined to appear frequently throughout software development. These patterns appear so often that they have become well documented and given names. I cannot recommend more highly the book Design Patterns by the "Gang of Four" as a resource on the topic of patterns. Recently I came across the need to combine to of the most common patterns, the decorator pattern and the template method pattern. I needed multiple implementation of a class to simultaneously coexist, the template method pattern, and I also needed to be able to decorate these classes, the decorator pattern. I noticed that while combining these two patterns, the decorator class behaves just as another class that implements the template method.
/* The template method */
interface AbstractClass
{
   void Method();
}

/* One implementation */
class ConcreteClass1 : AbstractClass
{
   public void Method()
   {
      System.Console.WriteLine("   ConcreteClass1");
   }
}

/* Second implementation */
class ConcreteClass2 : AbstractClass
{
   public void Method()
   {
      System.Console.WriteLine("   ConcreteClass2");
   }
}

/* Now comes the decorator, which feels just like any other implementation */
abstract class AbstractClassDecorator : AbstractClass
{
   public AbstractClassDecorator(AbstractClass abstractClass)
   {
      this.abstractClass = abstractClass;
   }

   public virtual void Method()
   {
      this.abstractClass.Method();
   }

   protected AbstractClass abstractClass;
}
Now it becomes time to implement the decorators. The nice thing about the decorator pattern is that it allows you to add decorators simply by extending a class. Here I have two decorators.
class ConcreteDecoratedAbstractClass1 : AbstractClassDecorator
{
   public ConcreteDecoratedAbstractClass1(AbstractClass abstractClass)
      : base(abstractClass)
   {
   }

   public override void Method()
   {
      this.abstractClass.Method();
      System.Console.WriteLine("   Decorator1");
   }
}

class ConcreteDecoratedAbstractClass2 : AbstractClassDecorator
{
   public ConcreteDecoratedAbstractClass2(AbstractClass abstractClass)
      : base(abstractClass)
   {
   }

   public override void Method()
   {
      this.abstractClass.Method();
      System.Console.WriteLine("   Decorator2");
   }
}
And now that the patterns are in place, all we have to do is simply use them. Because of the decoration and template pattern, we are able to create many possibilities to execute the "same" method. We can decorate or not decorate with any of the decorators, and we have multiple implementations of each method.
class Program
{
   static void Main(string[] args)
   {
      AbstractClass concrete1 = new ConcreteClass1();
      AbstractClass concrete2 = new ConcreteClass2();
      ConcreteDecoratedAbstractClass1 decorated1Concrete1 = new ConcreteDecoratedAbstractClass1(concrete1);
      ConcreteDecoratedAbstractClass1 decorated1Concrete2 = new ConcreteDecoratedAbstractClass1(concrete2);
      ConcreteDecoratedAbstractClass2 decorated2Concrete1 = new ConcreteDecoratedAbstractClass2(concrete1);
      ConcreteDecoratedAbstractClass2 decorated2Concrete2 = new ConcreteDecoratedAbstractClass2(concrete2);
      ConcreteDecoratedAbstractClass2 decorated21Concrete1 = new ConcreteDecoratedAbstractClass2(decorated1Concrete1);
      /* Et cetra */

      System.Console.WriteLine("Implementaiton 1");
      concrete1.Method();

      System.Console.WriteLine("Implementation 2");
      concrete2.Method();

      System.Console.WriteLine("Implementation 1 decorated by decorator 1");
      decorated1Concrete1.Method();

      System.Console.WriteLine("Implementation 2 decorated by decorator 1");
      decorated1Concrete2.Method();

      System.Console.WriteLine("Implementation 1 decorated by decorator 2");
      decorated2Concrete1.Method();

      System.Console.WriteLine("Implementation 2 decorated by decorator 2");
      decorated2Concrete2.Method();

      System.Console.WriteLine("Implementation 1 decorated by decorator 1 and decorator 2");
      decorated21Concrete1.Method();
}
This program outputs
Implementaiton 1
   ConcreteClass1
Implementation 2
   ConcreteClass2
Implementation 1 decorated by decorator 1
   ConcreteClass1
   Decorator1
Implementation 2 decorated by decorator 1
   ConcreteClass2
   Decorator1
Implementation 1 decorated by decorator 2
   ConcreteClass1
   Decorator2
Implementation 2 decorated by decorator 2
   ConcreteClass2
   Decorator2
Implementation 1 decorated by decorator 1 and decorator 2
   ConcreteClass1
   Decorator1
   Decorator2
I hope that this was informative in demonstrating the power of patterns and how they can be combined for even greater utility. Please feel free to comment below.
Post a Comment