previous up next Decorator

Intent, Motivation, Applicability, Structure, Participants, Collaborations, Consequences, Implementation, Sample Code, Known Uses, Related Patterns

previous next Sample Code

The following code shows how to implement user interface decorators in C++. We'll assume there's a Component class called VisualComponent.

class VisualComponent { public: VisualComponent(); virtual void Draw(); virtual void Resize(); // ... };
We define a subclass of VisualComponent called Decorator, which we'll subclass to obtain different decorations.
class Decorator : public VisualComponent { public: Decorator(VisualComponent*); virtual void Draw(); virtual void Resize(); // ... private: VisualComponent* _component; };
Decorator decorates the VisualComponent referenced by the _component instance variable, which is initialized in the constructor. For each operation in VisualComponent's interface, Decorator defines a default implementation that passes the request on to _component:
void Decorator::Draw () { _component->Draw(); } void Decorator::Resize () { _component->Resize(); }
Subclasses of Decorator define specific decorations. For example, the class BorderDecorator adds a border to its enclosing component. BorderDecorator is a subclass of Decorator that overrides the Draw operation to draw the border. BorderDecorator also defines a private DrawBorder helper operation that does the drawing. The subclass inherits all other operation implementations from Decorator.
class BorderDecorator : public Decorator { public: BorderDecorator(VisualComponent*, int borderWidth); virtual void Draw(); private: void DrawBorder(int); private: int _width; }; void BorderDecorator::Draw () { Decorator::Draw(); DrawBorder(_width); }
A similar implementation would follow for ScrollDecorator and DropShadowDecorator, which would add scrolling and drop shadow capabilities to a visual component.

Now we can compose instances of these classes to provide different decorations. The following code illustrates how we can use decorators to create a bordered scrollable TextView.

First, we need a way to put a visual component into a window object. We'll assume our Window class provides a SetContents operation for this purpose:

void Window::SetContents (VisualComponent* contents) { // ... }
Now we can create the text view and a window to put it in:
Window* window = new Window; TextView* textView = new TextView;
TextView is a VisualComponent, which lets us put it into the window:
window->SetContents(textView);
But we want a bordered and scrollable TextView. So we decorate it accordingly before putting it in the window.
window->SetContents( new BorderDecorator( new ScrollDecorator(textView), 1 ) );
Because Window accesses its contents through the VisualComponent interface, it's unaware of the decorator's presence. You, as the client, can still keep track of the text view if you have to interact with it directly, for example, when you need to invoke operations that aren't part of the VisualComponent interface. Clients that rely on the component's identity should refer to it directly as well.


Sample Code of Abstract Factory, Adapter, Bridge, Builder, Chain of Responsibility, Command, Composite, Decorator, Facade, Factory Method, Flyweight, Interpreter, Iterator, Mediator, Memento, Observer, Prototype, Proxy, Singleton, State, Strategy, Template Method, Visitor

previous next