Creating and Extending Objects With the Decorator Pattern

Creating and Extending Objects with the Decorator Pattern

DECORATOR-Pattern-1.jpg

Introduction

Sometimes we programmers think that if we could have been developed in such a manner then we would avoid these issues. In fact I have thought like this in the past. The reason behind this is very simple, without thinking of the entire project's requirements overall. Before writing the code if you build a picture in your mind of what the pieces of code are, how the pieces will interact and how the data will flow in all angles then the more you can picture the features architecturally, the more likely you will feel comfortable at the end. The solution is patterns.

Here we see the Decorator Pattern that allows the behavior to be added to an individual object, either statically or dynamically, without affecting the behavior of other objects from the same class.

Design Patterns

Design Patterns make our solution easily reusable, extendable and maintainable. Some programmer's mindset is to program to the problem, they want to provide a fix for the problem at the moment. There is no thinking in terms of reuse, extensibility and maintainability. This is where the problem usually occurs where most of programmers should be putting in more work to provide a temporary fix rather than solving the original problem in the long run.

As said in the "Design Pattern for Dummies", Designs Patterns are solutions to programming problems that automatically implement good design techniques. Someone has already encountered the issues you are encountering and have solved them and are willing to show you what the best techniques are. All we need to do is to recognize the right design pattern that fits your situation and lock into that.

DECORATORative Dialogue

Before I proceed to the source code explanation of the decorative pattern, here I give you a small dialogue between two persons BEVERAGE SELLER and CUSTOMER. Probably this would give you a broad view about Decorative Patterns.

DECORATOR-Pattern-2.jpg What would you like to have?

DECORATOR-Pattern-3.jpg Can I have a cup of tea?

DECORATOR-Pattern-2.jpg Yes, sure [starts making the tea in his place]

DECORATOR-Pattern-3.jpg Can you make it double strong?

DECORATOR-Pattern-2.jpg Patiently replied,"Yes Sir"[starts making the tea double strength]

DECORATOR-Pattern-3.jpg Let's make that a Ginger Tea

DECORATOR-Pattern-2.jpg Gives an angry look and starts making the tea from scratch

DECORATOR-Pattern-3.jpg Can you make it less strong with more Ginger in the tea?

DECORATOR-Pattern-2.jpg Gives an angry with disappointed look

DECORATOR-Pattern-3.jpgCan you pour some biscuit particles over the tea?

DECORATOR-Pattern-2.jpg Lost his patience and saying something unpleasant by seeing him

What do you understand from this dialogue? The changes keep coming from the customer saying this change I want, that one I want. Developers should always be adapting the changes coming in his way. That is the purpose of Design Patterns.

For the preceding dialogue example, a Decorator Pattern is the perfect pattern because it is all about extending the functionality of a given class. After you have written one class you can add decorators (additional classes) to extend the class; doing means that you will not need to continue to modify the original classes over and over again, so your tea can become a Ginger tea, double strength or light strength with no worries.

Keep your code closed for modification, so the main core code will not be modified, rather we can extend it when needed.
 

Customer asking a general TEA

Public class TEAProvider
{
    Public TEAProvider ()
    {
    }
    Public String OrderDetail ()
    { 
        Return "You are getting TEA";
    }
}

When the TeaProvider object is created, its order detail returns "you are getting TEA". This is very good for one type of customer. If another customer asks for double strength tea or Ginger tea then we need to change the program as in the following:

Customer asking Double strong TEA

Public class TEAProvider
{
    Public TEAProvider ()
    {
    }
    Public String OrderDetail ()
    {   
        Return "You are getting a double strong TEA";
    }
}

 

 

Customer asking Ginger TEA
Public class TEAProvider
{
    Public TEAProvider ()
    {
    }
    Public String OrderDetail ()
    {   
        Return "You are getting a ginger TEA";
    }
}

In the preceding model the programmer needs to change the code again and again. That is the problem here. So we will try to solve this problem using Decorator Patterns.

Applying Decorator Pattern

DECORATOR-Pattern-4.jpg

Core Component identification

As a first step we should determine the core functionality in our project, which is tea in this example, so we shall create a class called TEABase that inherits the class called Base. Our purpose is not to modify the existing class, the core component class should be closed and open for extension.

Abstract class : Base

Public abstract class Base
{
    Public abstract string OrderDetail ();
}

 

 

Core Component class : TEABase

Public class TEABase: Base
{
     Public String OrderDetail ()
     {   
         Return "TEA" ;
     }
}


Creation of decorator class


We will now create a DecoratorBase class that is a base for all other decorators, in other words, whichever functionalities are to be extended, you can extend it using decorators. In our case, the tea is going to be GingerTEA, DoubleStrongTEA.
So the decorator base class will be formed in the following manner:

Decorator Base class : DecoratorBase

Public abstract class DecoratorBase: Base
{     
    Protected Base BaseObj
    {
        get;
        set ;
    }       
    Public DecoratorBase (Base B)
    {    
        BaseObj = B;    
    }
}


For the purpse of consistency and uniqueness we have made DecoratorBase abstract, so the classes like GingerTEA and DoubleStrongTEA, whichever is being derived, must have the overridden function OrderDetail.

In the preceding method we have introduced a protected variable BaseObj, the Protected keyword is a member access modifier that is accessible within its class and by derived class instances, in our case we have used it to hold the component object and also the decorator objects.

Inheriting the Decorator

GingerTEA class Inherits DecoratorBase: GingerTEA

Public class GingerTEA: DecoratorBase
{     
    Public GingerTEA (Base B): base (B)
    {
    }
    Public Override string OrderDetail()
    { 
        return BaseObj.OrderDetail () +"With Ginger";
    }
}


 

DoubleStrongTEA class Inherits DecoratorBase

Public class DoubleStrongTEA: DecoratorBase
{     
    Public DoubleStrongTEA (Base B): base (B)
    {
    }
    Public Override string OrderDetail()
    { 
        return BaseObj.OrderDetail () +"With DoubleStrong";
    }
}


Final Implementation

Main Class

Public static void Main (string[] args)
{     
    Base B = new TEABase ();
    B= new GingerTEA (B);
    B = new DoubleStrongTEA (B);
    B.OrderDetail ();
}


You can see in the preceding implementation that you could find that all the classes are instantiated by the Base object. In the attached source code in debug mode you can very well understand that whenever the class is instantiated, the call goes to the DecoratorBase and the base object is what we pass from the decorator class that will be stored in the BaseObj, it will be accessible by the decorator class since it is a protected variable. If you feel like it, I am not good in explanations, please debug the attached source code and get that point.

REFER TO THE ATTACHED SOURCE CODE FOR FURTHER DETAILS

Summary

A decorator can be done by designing a new decorator class that wraps the original class; it's about attaching the additional responsibility to an object dynamically. It's a perfect pattern to sub classing for extending functionality.

Up Next
    Ebook Download
    View all
    Learn
    View all