Decorator
In object-oriented programming, the decorator pattern is a design pattern that allows new/additional behaviour to be added to an existing class dynamically.
The decorator pattern can be used to make it possible to extend (decorate) the functionality of a class at runtime. This works by adding a new decorator class that wraps the original class. This wrapping is achieved by
- Subclass the original "Component" class into a "Decorator" class
- In class Decorator, add a Component pointer as a field
- Pass a Decorator pointer to the Decorator constructor to initialize the Component pointer.
- In class Decorator, redirect all "Component" methods to the "Component" pointer. This implies that all Decorator fields coming from the Component motherclass will never be used and their memory space will be wasted. That is an accepted drawback of the decorator pattern.
- In class Decorator, override any Component method which behavior needs to be modified.
This pattern is designed so that multiple decorators can be stacked on top of each other, each time adding a new functionality to the overridden method. The decorator pattern is an alternative to subclassing. Subclassing adds behavior at compile time whereas decorating can provide new behaviour at runtime.
This difference becomes most important when there are several independent ways of extending functionality. In some object-oriented programming languages, classes cannot be created at runtime, and it is typically not possible to predict what combinations of extensions will be needed at design time. This would mean that a new class would have to be made for every possible combination. By contrast, decorators are objects, created at runtime, and can be combined on a per-use basis. An example of the decorator pattern is the Java I/O Streams implementation.
A Decorator, also known as a Wrapper, is an object that has an interface identical to an object that it contains. Any calls that the decorator gets, it relays to the object that it contains, and adds its own functionality along the way, either before or after the call. This gives you a lot of flexibility, since you can change what the decorator does at runtime, as opposed to having the change be static and determined at compile time by subclassing. Since a Decorator complies with the interface that the object that it contains, the Decorator is indistinguishable from the object that it contains. That is, a Decorator is a concrete instance of the abstract class, and thus is indistinguishable from any other concrete instance, including other decorators. This can be used to great advantage, as you can recursively nest decorators without any other objects being able to tell the difference, allowing a near infinite amount of customization.
Decorators add the ability to dynamically alter the behavior of an object because a decorator can be added or removed from an object without the client realizing that anything changed. It is a good idea to use a Decorator in a situation where you want to change the behaviour of an object repeatedly (by adding and subtracting functionality) during runtime.
