a DotNetStyling - .Net World by Armen Ayvazyan : Decorator Pattern
Welcome to DotNetStyling Sign in | Join | Help
Add to Technorati Favorites Add to Google Reader or Homepage Add to My AOL Subscribe in FeedLounge Subscribe in Bloglines Add to Excite MIX Add to flurry Add to Pageflakes Subscribe in NewsGator Online


Decorator Pattern

One of the beautiful patterns in GOF's (Gang Of Four) patterns bucket is a Decorator Pattern.  The purpose of Decorator pattern is to add extended functionality to the class without making any change in it. This is very useful technic especially when there are many classes derived from one base class which should contain new functionality. 

 

Diagram and Implementation

This is the diagram of Decorator Pattern.

image

Decorator is an abstract class which basically is a wrapper for a classes inherited from Component base class. It implements the abstract members of its base class by calling the appropriate methods of the instance of ConcreteComponent class which Decorator gets in constructor. It is sounds complicated by in real world it is very easy:

Component - an abstract class which contains abstract members for all inherited classes.

public abstract class Component

{

      public abstract void MethodA();

      public abstract void MethodB();

}

 

ConcreteComponent - concrete class with concrete implementation of abstract members of its base class.

public class ConcreteComponent : Component

{

      public override void MethodA()

      {

            //Implementation of MethodA

      }

 

      public override void MethodB()

      {

            //Implementation of MethodB

      }

}

 

DecoratorClass - this is the decorator which contains all members of the same Conponent base class like ConcreteComponent does with one exception that decorator does not have its own implementation but rather calls implementation of concrete component accepted in constructor.

public abstract class DecoratorClass : Component

{

      private Component _component;

      public DecoratorClass(Component component)

      {

            _component = component;

      }

 

      public override void MethodA()

      {

            _component.MethodA();

      }

 

      public override void MethodB()

      {

            _component.MethodB();

      }

}

As you can see the overridden methods of DecoratorClass will do exactly the same what instance of passed component does.

Note: Inheritance modifier of DecoratorClass is abstract. It will eliminate users to use DecoratorClass directly as it has no specific functionality but the same as ConcreteComponent does.

 

ConcreteDecorator - class contains members related to new extended functionality for Component based classes.

public class ConcreteDecorator : DecoratorClass

{

      public ConcreteDecorator(Component component): base(component)

      {

      }

 

      private int _someProperty;

 

      public int SomeProperty

      {

            get { return _someProperty; }

            set { _someProperty = value; }

      }

     

}

ConcreteDecorator will not just contain members for extended functionality but also there will be available all members of the ConcreteComponent passed as a instance to constructor. 

This is the code example how to use Decorator Pattern:

 

public class Test

{

      public Test()

      {

            ConcreteComponent component = new ConcreteComponent();     

            ConcreteDecorator concreteDecorator = new ConcreteDecorator(component);

           

            concreteDecorator.SomeProperty = 5;

            concreteDecorator.MethodA();

            concreteDecorator.MethodB();

      }

}

By executing methods of concreteDecorator we actually executing appropriate methods of component instance passed to concreteDecorator as input parameter.

I can see two main points in Decorator Pattern design.

  • We don't have a public pointer to ConcreteComponent inside of ConcreteDecorator but ConcreteDecorator becomes a ConcreteConponent with extra members. Which means we don't have to call ConcreteDecorator.ConcreteComponent.MethodA() but ConcrteDecorator.MethodA() which is slightly different from Architectural Design perspective.
  • ConcreteComponent not "should" but "could" support extended functionality. We can still use ConcreteComponent and it should work fine. And just in case when we need to use extended functionality for a ConcreteComponent we will use ConcreteDecorator instead. 

In a future of course we can have any number of new ConcreteComponents which could behave with extended functionality like current ConcreteComponent does. To achieve we just need inherit new classes from Component base class.

We can create new ConcreteDecorators with other functionality for ConcreteComponents just by creating a new ConcreteDecorator classes by inherited from DecoratorClass.

 

Real World Example

Use case scenario:

Assume there is a company which have some cars in garage which they are using for some internal purposes. But not all of them are used during the day and management decided to use  a cars left in garage like taxi to increase company's income. Which cars should be used as taxi depends on which of them will leave in garage unused in each morning of day. 

Implementation:

First of all we have to implement Car abstract class with abstract members belongs to car behavior. To have ability to drive the car each of concrete cars should have implemented two basic methods Start() and Drive(). So, our abstract Car class will contain Drive() and Start() abstract methods.

Each of the cars in garage should be inherited from the Car abstract base class and both methods should be implemented with the specific logic for each of appropriate car. Drive method of Honda car will have behavior specific for Honda car and Toyota will have Drive method implemented with specific behavior for Toyota.

 

image

 

 

This is implementation of the abstract class Car:

//Component

public abstract class Car

{

      public abstract void Start();

      public abstract void Drive();

}

Class representing Toyota car in our garage:

/// <summary>

/// Represent Toyota car.

/// </summary>

public sealed class Toyota : Car

{

      /// <summary>

      /// Start Toyota engine.

      /// </summary>

      public override void Start()

      {

            Console.WriteLine("Toyota has been started.");

      }

      /// <summary>

      /// Driving Toyota car.

      /// </summary>

      public override void Drive()

      {

            Console.WriteLine("Toyota is moving.");

      }

}

 

The class representing Honda car:

/// <summary>

/// Class represent Honda car.

/// </summary>

public sealed class Honda : Car

{

      /// <summary>

      /// Start the Honda engine.

      /// </summary>

      public override void Start()

      {

            Console.WriteLine("Honda has been started.");

      }

     

      /// <summary>

      /// Drive the car.

      /// </summary>

      public override void Drive()

      {

            Console.WriteLine("Honda is moving.");

      }

}

 

Now we have to implement logic related to Taxi behavior for both cars. There are a couple of reasons why we need to implement Decorator pattern to achieve our goal.

  • Considering that we could have more than two cars in our garage, implementation of taxi logic inside of all those concrete car will take a lot of time and after all we will have code redundancy.
  • Mostly cars should behave as a normal cars which means in some cases we won't use taxi related members at all. So implementation of taxi related members inside of the car class is not correct from Architectural perspective as class can contain a lot of empty members.
  • It is possible that in a future we will add some cars which should not be used like a taxi at all. So by implementing taxi related logic in it or in its base class is useless.
  • It is possible that cars would have some other extended functionality except of being a taxi. For instance it could be rent to other people or companies which means those car should contain the rent related logic inside.
  • Implementation of all new functionality should be as easy as possible without touching existing model. 

This is the right time when Decorator Pattern can help us to easily solve the problem.

 

First lets implement the Decorator itself. To implement decorator we will create a class Decorator which should derive from the same base class as our concrete cars (Honda, Toyota) do.

public abstract class Decorator : Car

{

      private Car _car;

      public Decorator(Car car)

      {

            _car = car;

      }

      /// <summary>

      /// Start the decorated car engine.

      /// </summary>

      public override void Start()

      {

            _car.Start();

      }

     

      /// <summary>

      /// Drive decorated car.

      /// </summary>

      public override void Drive()

      {

            _car.Drive();

      }

}

 

Next step is to implement class derived from the Decorator class with specific extended functionality. We call it TaxiCar and it will contains members specific to taxi functionality.

/// <summary>

/// Decorates a car to be a taxi.

/// </summary>

public sealed class TaxiCar : Decorator

{

      public TaxiCar(Car car) : base(car)

      {

      }

 

      private int _passengers;

      /// <summary>

      /// Number of passengers per single day.

      /// </summary>

      public int Passengers

      {

            get { return _passengers; }

            set { _passengers = value; }

      }

     

}

By implementing this we can instantiate any instance of car from our garage, pass it to TaxiCar class and use exactly that car like a taxi. By calling Start() or Drive() methods of TaxiCar instance we will use implementation of the concrete car we passed as a parameter in constructor during TaxiCar instantiation.

Of course there is a standard OOP way how to solve this problem. We could create Taxi class and inside have Car public property which will contain pointer to our Car class. But it is important to see that it is much more natural to have (or drive) TaxiCar by TaxiCar.Drive() than call Taxi.Car.Drive().

Let's say there was another decision from the management and they want to start using cars for rent. So, what we have to to it is just implement new "ConcreteDecorator" with a functionality related to rent. We will call this new class as RentedCar.

/// <summary>

/// Rented car.

/// </summary>

public sealed class RentedCar : Decorator

{

      private DateTime _rentedDateFrom;

      /// <summary>

      /// Date since when car is rented.

      /// </summary>

      public DateTime RentedDateFrom

      {

            get { return _rentedDateFrom; }

            set { _rentedDateFrom = value; }

      }

     

private DateTime _rentedDateTo;

      /// <summary>

      /// Date car rented to.

      /// </summary>

      public DateTime RentedDateTo

      {

            get { return _rentedDateTo; }

            set { _rentedDateTo = value; }

      }

     

      public RentedCar(Car car) : base(car)

      {

           

      }

}

Important: RentedCar and TaxiCar are still cars which means they can be driven by calling Drive() or Start() methods directly.

 
Final Diagram

This is the class diagram after final implementation:

image

 

Let's Start Drive the Car.

Now let's to see what we have done. In console application let's create two instances of the the car and use one for company's internal purposes and another one use like a taxi.

static void Main(string[] args)

{

      Honda h = new Honda();

                 

      h.Start();

      h.Drive();

 

      Toyota t = new Toyota();

 

      TaxiCar rc = new TaxiCar(t);

      rc.Passengers = 3;

      rc.Start();

      rc.Drive();

           

      Console.ReadLine();

}

 

image

Another Tip

As you could see we cannot have more than one instance of concrete car (Honda or Toyota) in the same time. Either it should be used like taxi or other purpose. To have just one instance in a same time we have to implement Singleton design pattern for each of the concrete cars we have (Honda, Toyota).

 

 

Resources

GOF Decorator Pattern

kick it on DotNetKicks.com Digg!

Posted: 27. září 2007 9:08 by admin

Comments

New Comments to this post are disabled