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 some time 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 explain 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:
Class1 objA = new Class1();
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
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:
Class TestCalss : Class1
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 methodology 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.
Lets see what is the textbook definition of the decorator pattern is and then one can compare it to the above example to get the grasp of the concept:
1) “Decorator provide a flexible alternative to sub-classing for extending functionality”
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
This class diagram shows the implementation of decorator pattern for the listing 2. 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 is the component.
TestClass extends or inherit from the C
lass1 as well as it contains a reference (composition) of C
lass1. 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 diagaram:
Prevent Class explosion
Suppose you have four classes which extend from the same super-class. Let's suppose a new class is required which add to some functionality to a superclass. In order to implement you need to implement this for the 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 this changed. 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 that some files contain a specific word at the start other contain frame specific word at the end. You will need to extend from the same class and the class diagram will look like this:
Let’s suppose there is another system for a binary file is available. Now we have four more classes such as
frameSyncChineseFilesBinarySystem and 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 above example we can create 2 component,
ChineseFileSystem French File system and 2 decorator 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 component (e.g. Chinese File System) as well as wrap frame sync with all component. We can also wrap multiple times such as wrapping
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 class(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 easier to implement can easily utilize the Java IO library.
In .net it seems like the streaming library uses decorator pattern but there is a minor difference.
In the .net class diagram for IO library
NetworkStream are component classes whereas
BinaryWriter acts 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
NetworkStream but it does not extend the base stream class. It simply contains the stream. This looks good because no one wants to wrap
BinaryReader together and there is no need for type matching.
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. To learn more about object oriented design pattern visit www.linesperday.com.
Book "Design Patterns: Elements of Reusable Object-oriented Software" by Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides.
Learn more about object oriented design patterns and principles here.