Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I was reading a programming article and it mentioned the Decorator pattern. I've been programming for awhile but without any kind of formal education or training, but I'm trying to learn about the standard patterns and such.

So I looked up the Decorator, and found a Wikipedia article on it. I now understand the concept of the Decorator pattern, but I was a bit confused by this passage:

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 adds this functionality to existing Window objects. At this point, either solution would be fine.

Now let's assume we also desire the ability 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 simply create a new BorderedWindowDecorator—at runtime, we can decorate existing windows with the ScrollingWindowDecorator or the BorderedWindowDecorator or both, as we see fit.

OK, when they say to add borders to all windows, why not just add functionality into the original Window class to allow for the option? The way I see it is, subclassing is just for adding specific functionality to a class, or overriding a class method. If I needed to add functionality to all existing objects, why wouldn't I just modify the superclass to do so?

There was another line in the article:

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 run-time for individual objects.

I don't get where they say "...the change affects all instances of the original class" -- how does subclassing change the parent class? Isn't that the whole point of subclassing?

I'm going to assume that the article, like many Wiki's, is just not written clearly. I can see the usefulness of the Decorator in that last line - "...provide new behavior at run-time for individual objects."

Without having read about this pattern, if I needed to change behavior at run-time for individual objects, I would have probably built some methods into the super- or subclass to enable/disable said behavior. Please help me really understand the usefulness of the Decorator, and why my newbie thinking is flawed?

share|improve this question
    
appreciate the edit, Walter... fyi, I used "guys" not to exclude women, but as an informal greeting. –  Jim Jun 2 '11 at 14:43
    
The edit would just be to remove the greeting in general. It's not standard SO/SE protocol to use one in questions [don't worry, we don't think it rude to jump straight into the question] –  Farrell Jun 2 '11 at 14:46
    
cool, thanks! it was just that he tagged it "removing gender" and I'd hate anyone to think I am misogynistic or something!! :) –  Jim Jun 2 '11 at 14:57

3 Answers 3

up vote 12 down vote accepted

The decorator pattern is one that favours composition over inheritance [another OOP paradigm that is useful to learn about]

The main benefit of the decorator pattern - over subclassing is to allow more mix & match options. If you have, for instance, 10 different behaviours that a window can have, then this means - with subclassing - you need to create every different combination, which will also inevitably include a lot of code reuse.
However, what happens when you decide to add in a new behaviour?

With the decorator, you just add a new class which describes this behaviour, and that's it - the pattern allows you to effectively drop this in without any modification to the rest of the code.
With sub-classing, you've got a nightmare on your hands.
One question you asked was "how does subclassing change the parent class?" It's not that it changes the parent class; when it says an instance, it means any object you've 'instantiated' [if you're using Java or C#, for instance, by using the new command]. What it's referring to is, when you add these changes to a class, you've got no choice for that change to be there, even if you don't actually need it.

Alternatively, you can put all his functionality into a single class with it turned on/off via flags... but this ends up with a single class that becomes larger and larger as your project grows.
It's not unusual to start your project this way, and refactor into a decorator pattern once you hit an effective critical mass.

An interesting point that should be made: you can add the same functionality multiple times; so you could, for instance, have a window with double, triple or whatever amount or borders as you require.

The major point of the pattern is to enable run-time changes: you may not know how you want the window to look until the program is running, and this allows you to easily modify it. Granted, this can be done via the subclassing, but not as nicely.
And finally, it allows for functionality to be added to classes that you may not be able to edit - for example in sealed/final classes, or ones provided from other APIs

share|improve this answer
2  
Thanks, Farrell - when you say "Alternatively, you can put all his functionality into a single class with it turned on/off via flags... but this ends up with a single class that becomes larger and larger as your project grows." that made it click for me. I think part of the issue is I've never worked on a class that got so big the decorator made sense to me. Thinking big, I can definitely see the benefits...thanks! –  Jim Jun 2 '11 at 14:53
    
Also, the part about sealed classes makes tons of sense...thanks! –  Jim Jun 2 '11 at 14:54

Consider the possibilities of adding scrollbars and borders with subclassing. If you want every possibility, you get four classes (Python):

class Window(object):
    def draw(self):
        "do actual drawing of window"

class WindowWithScrollBar(Window):
    def draw(self):
        Window.draw(self)
        "do actual drawing of scrollbar"

class WindowWithBorder(Window):
    def draw(self):
        Window.draw(self)
        "do actual drawing of border"

class WindowWithScrollBarAndBorder(Window):
    def draw(self):
        WindowWithScrollBar.draw(self)
        WindowWithBorder.draw(self)

Now, in WindowWithScrollBarAndBorder.draw(), the window get's drawn twice, and the second time it may or may not overwrite the already drawn Scrollbar, depending on the implementation. So your derived code is tightly coupled to the implementation of another class, and you have to care about that everytime you alter the Window class behaviour. A solution would be to copy-paste the code from the super classes tho the derived classes and adjust it to the derived classes needs, but every change in a super class must be copy-pasted again and adjusted again, so again the derived classes are tightly coupled to the base class (via the need for copy-paste-adjust). Another problem is that if you need yet another property that a window may or may not have, you have to double every class:

class Window(object):
    ...

class WindowWithGimmick(Window):
    ...

class WindowWithScrollBar(Window):
    ...

class WindowWithBorder(Window):
    ...

class WindowWithScrollBarAndBorder(Window):
    ...

class WindowWithScrollBarAndGimmick(Window):
    ...

class WindowWithBorderAndGimmick(Window):
    ...

class WindowWithScrollBarAndBorderAndGimmick(Window):
    ...

That means for a set of mutually independet features f with |f| being the number of features, you have to define 2 ** |f| classes, eg. if you have 10 features you get 1024 tightly coulped classes. If you use the Decorator Pattern, every feature get's its own independent and loosely coupled class and you have only 1 + |f| classes (that's 11 for the example above).

share|improve this answer
    
See, my thinking wouldn't be to keep adding classes - it would be to add the funtionality to the original (sub)class. so in class Window(object): you have scrollBar = true, border = false, etc... The answer Farrell shows me where that can go wrong, however - just leading to bloated classes and such...thanks for the answer, +1! –  Jim Jun 2 '11 at 14:46
    
well, +1 once I have the rep to do so! –  Jim Jun 2 '11 at 14:54

I'm not an expert on this particular pattern, but as I see it the Decorator pattern can be applied to classes that you may not have the ability to modify or sub-class (they may not be your code and be sealed, for instance). In your example, what if you didn't write the Window class but are just consuming it? So long as the Window class has an interface and you program against that interface your Decorator can use the same interface but extend the functionality.

The example you mention is actually covered here quite neatly:

Extending an object's functionality can be done statically (at compile time) by using inheritance however it might be necessary to extend an object's functionality dynamically (at runtime) as an object is used.

Consider the typical example of a graphical window. To extend the functionality of the graphical window for example by adding a frame to the window, would require extending the window class to create a FramedWindow class. To create a framed window it is necessary to create an object of the FramedWindow class. However it would be impossible to start with a plain window and to extend its functionality at runtime to become a framed window.

http://www.oodesign.com/decorator-pattern.html

share|improve this answer
    
great link, thanks!! –  Jim Jun 2 '11 at 14:55

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.