Understanding and Implementing Decorator Pattern in C#

This article talks about the basics of decorator pattern and see when this pattern can be found useful. We will also work on a rudimentary implementation of Decorator Pattern in C#.

Background

There are some occasions in our applications when we need to create an object with some basic functionality in such a way that some extra functionality can be added to this object dynamically. For example, Lets say we need to create a Stream object to handle some data but in some cases we need this stream object to be able to encrypt the stream in some cases. So what we can do is that we can have the basic Stream object ready and then dynamically add the encryption functionality when it is needed.

One may also say that why not keep this encryption logic in the stream class itself and turn it on or off by using a Boolean property. But this approach will have problems like – How can we add the type custom encryption logic inside a class? Now this can be done easily by subclassing the existing class and have custom encryption logic in the derived class.

This is a valid solution but only when this encryption is the only functionality needed with this class. But what if there are multiple functionalities that could be added dynamically to this class and also the combination of functionalities too. If we use the subclassing approach then we will end up with derievd classes equal to the number of combination we could have for all our functionalities and the actual object.

This is exactly the scenario where the decorator patter can be useful. GoF defines Decorator pattern as “Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.

Before looking into the details of decorator pattern let us go ahead and see the class diagram of this pattern and see what each class is responsible for.

GoFClassDiagram

  • Component: It defines the interface of the actual object the need fucntionalities to be added dynamically to the ConcreteComponents.
  • ConcreteComponent: The actual object in which the functionalities could be added dynamically.
  • Decorator: This defines the interface for all the dynamic functionalities that can be added to the ConcreteComponent
  • ConcreteDecorator: All the functionalities that can be added to the ConcreteComponent. Each needed funcitonality will be one ConcreteDecoratorclass.

Using the code

To understand the decorator pattern let us look at an example of a billing system of a Bakery. This Bakery specializes in Cakes and Pastries. Customers can buy cakes and pastries and then choose to have extra stuff added on the base product. The extra Product are Cream, Cherry, Scent and Name card.

Now if we take the classic approach of subclassing to create this billing system we will end up with classes like

    • CakeOnly

 

  • CakeWithCreamAndCherry
  • CakeWithCreamAndCherryAndScent
  • CakeWithCreamAndCherryAndScentAndNameCard
  • CakeWithCherryOnly
  • PastryOnly
  • PastryWithCreamAndCherry
  • PastryWithCreamAndCherryAndScent
  • PastryWithCreamAndCherryAndScentAndNameCard
  • PastryWithCherryOnly 

 

  • AND MANY MANY MORE…………..

Not only this approach is a development problem this is a maintenance nightmare. creating and maintaining these sets of classes will be a very big problem. So let us see how we can elegantly design this solution by using Decorator Pattern.

Let us start by creating the Componentinterface.

This class defines the interface of the actual object the need functionalities to be added dynamically to ConcreteComponents. So let us now create the ConcreteComponentclasses.

Now we have our base object ready. Now we will look into how the other required things can be added to it dynamically. Lets start by looking at the Decoratorclass.

There are two things to notice here. First that this class implements the BakeryComponentinterface. The reason for that is a Cake with a Component will also be a cake and thus all the operations possible on a cake should also be possible on a Decorated cake. The second interesting thing to note is that it also hold the BakeryComponentobject inside. The reason for that is that we need the logical is-a relationship between a cake and a decorating item but since actually that is not the case we hold a BakeryComponentobject inside to be able to mimic that is-a relationship.

In short what we have done is that instead of having a static is-a relationship using inheritance, we have a dynamic is-a relationship by using composition.

Let us now see how the ConcreteDecoratorscan be implemented.

Now in these classes we have simply set the decorator specific values of the items and not customized any behavior. But if we want we can even customize the behavior or add more state variables in the ConcereteDecoratorobjects. To illustrate this point lets say whenever the customer choose to add the Namecard on his cake he is eligible to get a discount card for the next purchase and we need to show this message in the receipt. Lets see how the ConcreteDecoratorwill add its own state and behavior in that case.

Now our client application can create combination of these ConcreteComponentswith any Decorator. Lets look at the sample code implementation for the client.

And when we run the application.

Screenshot

Before wrapping up lets look at how our sample application is implementing the decorator pattern in terms of class diagram and lets compare it with the class diagram of decorator pattern.

OurClassDiagram

Point of Interest

In this introductory article we have looked into the decorator pattern. When can it be useful and how can we implement the decorator pattern in C#. Decorator pattern is a very good example of Open-Closed principle where all our classes are Open for extension but closed for modification. I hope this has been informative.

Download sample code for this article: DecoratorSampleApp