views:

74

answers:

2

I'm going over some design pattern questions and I looked at the definition and examples of the Decorator Pattern in GoF. It says

Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.

It gives examples of Decorators which use inheritance which is definitely not dynamic, however.

NetObjectives commits the same error:

http://www.netobjectives.com/PatternRepository/index.php?title=TheDecoratorPattern

The Portland Pattern Repository discussion of the Decorator indicates that there is confusion about what is and is not a decorator

http://c2.com/cgi/wiki?DecoratorPattern

Wikipedia makes some sense of this contradiction by noting that the delegate inside the Decorator should be set at construction time (other DI techniques would also work)

http://en.wikipedia.org/wiki/Decorator_pattern

All examples of the Decorator pattern (in Java or C++) require a static construct either through inheritance or by implementing an interface. The explanation in GoF says that the additional responsibilities are attached dynamically, however. But this is simply wrong.

The comments at PPR talk about dynamic languages that can add methods at runtime, but Java and C++ aren't dynamic and the explanation of Decorator does not say it is limited to dynamic languages like Groovy and Lisp.

Wouldn't a correct explanation of Decorator say that in languages that don't support dynamic method creation both static and dyanmic constructs are involved?

GoF's explanation is simply wrong as shown by their own examples, or have I misunderstood something?

+5  A: 

Dynamic I think the word 'dynamic' has come to mean something different than when the GOF wrote the book. I guess what they intended to say was 'adding pre/post behavior to an object without actually modifying the code/definition of the underlying object.' To clients the object (decorated or not) appears to be the same. Today dynamic is associated with dynamic languages and in that sense, means loose typing and ability to add methods / behavior to an object at runtime.

Alternative to subclassing

The decorator pattern is an alternative to subclassing. Subclassing adds behavior at compile time, and the change affects all instances of the original class; decorating can provide new behavior at runtime for individual objects.

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, at design time, what combinations of extensions will be needed. 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. -- wikipedia

Decorators employ inheritance however they do not inherit from the object that they are decorating. They inherit the common interface so as to expose the same methods as a decorated object (impersonation). They use composition for behavior - add pre-post behavior via delegation.

var dao = new PerformanceTrackingDecorator(new TurboSpeedDecorator(SqlDataAccessObject))
// use dao and later..
dao = new PerformanceTrackingDecorator(new TurboSpeedDecorator(XmlDataAccessObject))
//at runtime, I've added certain behavior to Sql and Xml DAOs
Gishu
+1. It's an implementation of the Open/Closed Principle. http://en.wikipedia.org/wiki/Open/closed_principle
TrueWill
If you look at the examples in GoF they do inherit from the object that they are decorating. They do so even after saying that Decorator is an alternative to subclassing. Another contradiction in their explanation of Decorator.
Dean Schulze
@Dean, in the Decorator examples in GoF, an abstract component class has derivatives which are concrete component classes and an abstract decorator class. The abstract decorator class has derivatives which are concrete decorator classes. The decorator classes do not inherit, neither directly nor indirectly, from concrete component classes.
Huperniketes
@Huperniketes, The point is that Decorator depends on inheritance, and is therefore not entirely dynamic. GoF's explanation is misleading at best.
Dean Schulze
@Dean I don't have the GOF book at hand currently.. maybe we're being a bit pedantic ; I think the idea itself is quite sound and useful. Their 'dynamic'ness stems from the ability to compose different combinations of decorators wrapping a concrete object at runtime, i.e. not having to create those many static derivations (as many combinations are possible) at compile-time. **Static languages need inheritance to make 2 objects look alike to a caller/client.** Decorators cannot replace inheritance however they can minimise abuse.
Gishu
@Dean, not "entirely" dynamic? It seems like you've adopted some unduly narrow definition for dynamic. A decorator provides modification of an object's behavior by means of redirection, through use of a wrapper. (In fact, the only difference between the Proxy and Decorator patterns is a proxy restricts the behavior or access to an object and a decorator extends it.) How the decorator's behavior is derived isn't central to the pattern's dynamism. How the component's behavior is extended **is**.
Huperniketes
@Huperniketes, Inheritance is static, not dynamic. Do you agree? You can't implement the Decorator pattern with just dynamic methods like DI because the Decorator has to be interface compatible with the decorated object (they both have the same base class or implement the same interface).
Dean Schulze
@Dean, the point isn't whether inheritance is static (which it is). The point is that the behavior is "added" to the object by wrapping it with another object which responds to the messages before the concrete component. _That_ is what makes it dynamic.
Huperniketes
A: 

It looks like GoF's explanation is just badly written. Calling Decorator an alternative to subclassing when their examples are subclasses is very confusing.

GoF says that the decorated object and its Decorators must have conforming interfaces. Apparently this is a requirement of the pattern, and they demonstrate this with inheritance. So there is both a dynamic and static component to their Decorator pattern.

I could also see how you could invert the pattern and make the Decorator(s) a delegate of the decorated object but this would probably result in a convoluted implementation.

In a dynamic language like Lisp or Groovy I think you could just merge the decoration logic into the draw() logic of the class itself. The requirement for interface conformance would not be necessary, nor would it be necessary to have separate classes for decorated object and Decorator.

I'm going to add learning Lisp to my Bucket List so I can see how design patterns change in a dynamic language.

Dean Schulze