Click here to Skip to main content
15,885,916 members
Articles / Programming Languages / C#
Tip/Trick

Decorator Design Pattern

Rate me:
Please Sign up or sign in to vote.
2.64/5 (13 votes)
11 Dec 2018CPOL6 min read 26K   23   7
Explaining Decorator Design pattern and its implementation

Introduction

The easiest way to extend some feature of a Class is to use inheritance. But with inheritance, it became very difficult to change the code or even sometimes extend the functionalities. One better solution to overcome some of the deficiencies of inheritance is to use decorator design pattern. This article explains what decorator design pattern is and explains its implementation. The user will learn about the decorator pattern, some of its advantages and how it is implemented in some frameworks such as Java or .NET.

This article will explain the definition of the decorator design pattern and its class diagram and then briefly describe its implementation in Java and .NET.

What is Decorator Design Pattern

We use composition in decorator pattern and what is composition? Consider the following example:

C#
// Listing 1

Class TestClass{  

    Class1 objA = new Class1();
	Void myOwnMethod()
    {
      // do some work before
	  objA.SomeOneOhterMethod();
      // do some my own work after..
     }
}  

In this example, code TestClass refers to Class1 This is called composition. Composition means holding the reference to another class. My choice of class names in bad, but for the sake of simplicity, stick with it.

We use inheritance to extend the functionality of any class. In a similar way, we can use composition to extend the functionality of any class. For example, in the above example, TestClass can extend the functionality of Class1 by simply calling the method of Calss1 and adding its own behavior before or after the method call of Class1 object.

Let’s look at the implementation of how can we use inheritance to write code that is similar to the above code listing in terms of functionality:

C#
// Listing 2
//Parent Class
Class Class1
{
 void  SomeOneOhterMethod() 
 {
	// Base class implementation
 }
}

// Child class
Class TestCalss : Class1
{
 void myOwnMethod()
 {
  // some sub-class own work before
   Base.SomeOneOtherMethod();
  // some sub-call own work after..
 }
}

As you can see, I can use both inheritance and composition to extend the behavior.

Now, let's move to another concept which is called polymorphism or type matching. When using inheritance, one can use the base class in place of its children class. In the second example, you can use the reference of base class Class1 to hold the reference of child class TestClass. But in the composition example above (first code listing), you can’t use Class1 in place of TestClass because both classes are of different types.

Here, if I ask you, can you find a way that you can utilize the benefit of type matching and composition at the same time, what would you do? Think about it. You can either use composition or inheritance to achieve the reusability and both come with their advantages and disadvantages. But if you find a way to take the benefits of both methodologies, then what would you do?

Decorator design pattern is an answer to that question.

In decorator pattern, we used composition for extending behavior whereas uses inheritance for matching the type.

Let's see what is the textbook definition of the decorator pattern and then one can compare it to the above example to get the grasp of the concept:

  1. “Decorator provides a flexible alternative to sub-classing for extending functionality”
    AND:
  2. “The decorator pattern attaches additional responsibilities to an object at dynamically.”

This second line of definition explains in the advantages of the decorator pattern.

Class Diagram and Implementing Guidelines

Image 1

This class diagram shows the implementation of decorator pattern for listing 2. This is a very simple example that shows how can we add benefit for both inheritance and composition in one place.

In this diagram above, TestCalss is the decorator to Class1 and Class1 is the component. TestClass extends or inherit from the Class1 as well as it contains a reference (composition) of Class1. This reference is used to add any additional behavior and inheritance is used for type matching.

Now, let’s look at the textbook class diagram and compare it with the above diagram:

Image 2

Advantages

Prevent Class Explosion

Suppose you have four classes which extend from the same super-class. Let's suppose a new class is required which adds to some functionality to a superclass. In order to implement, you need to implement this for all the four classes. In this way, you have four new classes for additional functionality for each implementing class. Similarly, all four classes need 16 classes to cater to this change. In total, you have 20 Classes to implement and maintain.

Take, for instance, you have a file type and two classes that extend them Chinese and French file system. Now after some time, you know that some files contain a specific word at the start, others contain frame specific word at the end. You will need to extend from the same class and the class diagram will look like this:

Image 3

Let’s suppose there is another system for a binary file that is available. Now we have four more classes such as frameSyncChineseFilesBinarySystem, etc.

This causes four more classes to extend the same base class and will result in a huge number of classes. By using decorator pattern, we can eliminate these problems. For the above example, we can create 2 components, ChineseFileSystem French File system and 2 decorators around them one is for frame sync and one is for a Binary system. This will reduce the number of classes. We can wrap this BinarySystem File with all components (e.g., Chinese File System) as well as wrap frame sync with all components. We can also wrap multiple times such as wrapping chinesefileSystem with FrameSync and then with Binary File System.

Hence, by not using inheritance and using composition, we prevented the syndrome of too many classes in a design.

New Behavior Can Be Added Dynamically

Since we use composition for adding behavior to the component classes, we can add behavior (even remove) behavior at run-time. Since we have to create the reference to an object at run-time, therefore, we can add or remove the behavior dynamically. On the other side in inheritance, we have to describe the behavior at compile time.

Inheritance for Type Matching So That One Can Mix and Match

Inheritance is used for type matching because in this way, the wrapping (decorator) class can be put in the place of the component class. Because inheritance allows us that base class reference can hold the child object and decorator is a child to the component. Hence, we can retain the benefit of inheritance with the help of decorator design pattern.

Implementations Within .NET and JAVA Framework

Decorator pattern is implemented in Java IO library. If you understand the concept of decorator design patterns, then one can realize different classes’ as wrappers and component. In this way, it becomes extremely easy to implement and can easily utilize the Java IO library.

In .NET, it seems like the streaming library uses decorator pattern, but there is a minor difference.

Image 4

In the .NET class diagram for IO library, FileStream and NetworkStream are component classes whereas BinaryReader and BinaryWriter act as the wrapper classes. The wrapper can add new functionality component at run-time since we pass the object of the component during run-time.

The difference is that BinaryReader wraps FileStream and NetworkStream but it does not extend the base stream class. It simply contains the stream. This looks good because no one wants to wrap BinaryWriter and BinaryReader together and there is no need for type matching.

Conclusion

In this article, I explain the decorator pattern in a very simplified form as well as briefly describe its implementation in Java and .NET Framework.

Reference

  • Book "Design Patterns: Elements of Reusable Object-oriented Software" by Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Pakistan Pakistan
If you want to learn more about object-oriented design, programming using real-life and real-world examples then you should visit:

www.linesperday.com

You will know what it takes to be great at programming and what lies ahead in your career: Is that money, authority or fame?

My name is Muhammad Umair and I write about programming, programmers, and object-oriented design and how you can optimize your programming skills to advance your programming career.

Comments and Discussions

 
Questionit could be better Pin
Southmountain23-Feb-18 11:40
Southmountain23-Feb-18 11:40 
GeneralMy vote of 1 Pin
Jason Storey19-Dec-13 5:11
Jason Storey19-Dec-13 5:11 
GeneralRe: My vote of 1 Pin
omeecode19-Dec-13 6:16
omeecode19-Dec-13 6:16 
GeneralMy vote of 2 Pin
Oshtri Deka19-Dec-13 0:45
professionalOshtri Deka19-Dec-13 0:45 
Decorator pattern and wrappers in general are very straight-forward, but this article is not.
Perhaps too much caffeine affected my judgement, but I'm trying to read it as an beginner would and I don't feel well informed.
GeneralRe: My vote of 2 Pin
omeecode19-Dec-13 6:17
omeecode19-Dec-13 6:17 
QuestionI am not voting, but... Pin
Paulo Zemek15-Dec-13 17:12
mvaPaulo Zemek15-Dec-13 17:12 
AnswerRe: I am not voting, but... Pin
omeecode15-Dec-13 19:47
omeecode15-Dec-13 19:47 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.