Design Patterns
- Decorator Pattern
bogotobogo.com site search:
Decorator Pattern
Intent
Attach additional responsibilities to an object dynamically.
Decorators provide flexible alternatives to subclassing for extending functionality.
#include <iostream> #include <string> using namespace std; class Window { public: virtual void draw() = 0; virtual string getDescription() = 0; virtual ~Window() {} }; class SimpleWindow : public Window { public: void draw() { // draw window } string getDescription() { return "simple window\n"; } }; class WindowDecorator : public Window { protected: Window *m_decoratedWindow; public: WindowDecorator (Window *decoratedWindow): m_decoratedWindow(decoratedWindow) {} }; class VerticalScrollBarDecorator : public WindowDecorator { public: VerticalScrollBarDecorator (Window *decoratedWindow): WindowDecorator(decoratedWindow) {} void draw() { drawVerticalScrollBar(); m_decoratedWindow->draw(); } string getDescription() { return m_decoratedWindow->getDescription() + "with vertical scrollbars\n"; } private: void drawVerticalScrollBar() { // draw the vertical scrollbar } }; class HorizontalScrollBarDecorator : public WindowDecorator { public: HorizontalScrollBarDecorator (Window *decoratedWindow): WindowDecorator(decoratedWindow) {} void draw() { drawHorizontalScrollBar(); m_decoratedWindow->draw(); } string getDescription() { return m_decoratedWindow->getDescription() + "with horizontal scrollbars\n"; } private: void drawHorizontalScrollBar() { // draw the horizontal scrollbar } }; int main() { Window *simple = new SimpleWindow(); cout << simple -> getDescription() << endl; Window *horiz = new HorizontalScrollBarDecorator ( new SimpleWindow()); cout << horiz -> getDescription() << endl; Window *vert = new VerticalScrollBarDecorator ( new SimpleWindow()); cout << vert -> getDescription() << endl; Window *decoratedWindow = new HorizontalScrollBarDecorator ( new VerticalScrollBarDecorator(new SimpleWindow())); cout << decoratedWindow -> getDescription() << endl; return 0; }
Output:
simple window simple window with horizontal scrollbars simple window with vertical scrollbars simple window with vertical scrollbars with horizontal scrollbars
Let's take a look at code with the class diagram.
- Each component (Window) can be used on its own, or wrapped by decorator.
- The ConcreteComponent (SimpleWindow) is the object we're going to dynamically add new behavior (vertical/horizontal scrollbars) to. It inherits Component.
class SimpleWindow : public Window
- Each decorator has-a (wraps) a component, which means the decorator has an instance variable that holds a pointer to a component.
class WindowDecorator : public Window { protected: Window *m_decoratedWindow; ...
- Decorators implement the same interface or abstract class as the component they are going to decorate.
- The ConcreteDecorator has an instance variable for the thing it decorate (the Component the Decorator wraps).
class VerticalScrollBarDecorator : public WindowDecorator { public: VerticalScrollBarDecorator (Window *decoratedWindow): WindowDecorator(decoratedWindow) {} void draw() { drawVerticalScrollBar(); m_decoratedWindow->draw(); } string getDescription() { return m_decoratedWindow->getDescription() + "with vertical scrollbars\n"; } ... };
Ph.D. / Golden Gate Ave, San Francisco / Seoul National Univ / Carnegie Mellon / UC Berkeley / DevOps / Deep Learning / Visualization