Wednesday, February 28, 2007

Decorator Pattern

In object-oriented programming, the decorator pattern is a design pattern that allows new/additional behavior to be added to an existing method of an object dynamically.

Introduction

The decorator pattern works by wrapping the new "decorator" object around the original object, which is typically achieved by passing the original object as a parameter to the constructor of the decorator, with the decorator implementing the new functionality. The interface of the original object needs to be maintained by the decorator.
Decorators are alternatives to subclassing. Subclassing adds behaviour at compile time whereas decorators provide a new behaviour at runtime.

Motivation (Good example..do read)

As an example, consider a window in a windowing system. To allow scrolling of the window's contents, we may wish to add horizontal or vertical scrollbars to it, as appropriate. Assume windows are represented by instances of the Window class, and assume this class has no functionality for adding scrollbars. We could create a subclass ScrollingWindow that provides them, or we could create a ScrollingWindowDecorator that merely adds this functionality to existing Window objects. At this point, either solution would be fine. (Another solution is to simply modify the existing Window class, but this is not always possible—we might not have access to its implementation, or we might be adding storage overhead for new functionality that the majority of objects will not use.)

Now let's assume we also wish the option to add borders to our windows. Again, our original Window class has no support. The ScrollingWindow subclass now poses a problem, because it has effectively created a new kind of window. If we wish to add border support to all windows, we must create subclasses WindowWithBorder and ScrollingWindowWithBorder. Obviously, this problem gets worse with every new feature to be added. For the decorator solution, we need merely create a new BorderedWindowDecorator—at runtime, we can decorate existing windows with the ScrollingWindowDecorator or the BorderedWindowDecorator or both, as we see fit.



Implementaion

If the subject class is heavyweight, with lots of data or methods, it may make decorators too costly. Instead of changing the skin of the object, you can change the guts, via the Strategy pattern. Strategies do not have to conform to the subject's interface. The Strategy pattern can always replace the Decorator pattern, but it requires more anticipation. The Decorator pattern requires virtually no anticipation.


Consequences

· A subject and its decorators are decoupled. The author of the subject does not need to do anything special for it to be decorated. Similarly, decorators do not need to prepare for being decorated.

· It is easy to add any combination of capabilities. The same capability can even be added twice. This is difficult with inheritance.

· The same object may be simultaneously decorated in different ways. Clients can choose what capabilities they want by sending messages to the appropriate decorator.

· Objects do not pay for capabilities they do not use. Thus we have efficiency and generality at the same time.

· While a decorator has the same interface as its subject, it is not the same object. Hence object identity is not compatible with decorators. This also makes it hard to add a new decorator at run-time, since all client pointers must be changed. See the Implementation section for a remedy.

· Delegation may be required for self calls to work properly.