Reputation: 10303
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?
Upvotes: 4
Views: 1714
Reputation: 10303
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.
Upvotes: 0
Reputation: 136613
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
Upvotes: 6