Decorator

Intent

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

- Client-specified embellishment of a core object by recursively wrapping it.

- Wrapping a gift, putting it in a box, and wrapping the box.

Appilication

- You want to add behavior or state to individual objects at run-time. Inheritance is not feasible because it is static and applies to an entire class.

- With inheritance, the classes need to be created for every possible class with multiple responsibility.

Structure

The client is always interested in CoreFunctionality.doThis(). The client may, or may not, be interested in OptionalOne.doThis() and OptionalTwo.doThis(). Each of these classes always delegate to the Decorator base class, and that class always delegates to the contained “wrappee” object.

Checklist

- Ensure the context is: a single core (or non-optional) component, several optional embellishments or wrappers, and an interface that is common to all.

- Create a “Lowest Common Denominator” interface that makes all classes interchangeable.

- Create a second level base class (Decorator) to support the optional wrapper classes.

- The Core class and Decorator class inherit from the I interface.

- The Decorator class declares a composition relationship to the I interface, and this data member is initialized in its constructor.

- The Decorator class delegates to the I object.

- Define a Decorator derived class for each optional embellishment.

- Decorator derived classes implement their wrapper functionality - and - delegate to the Decorator base class.

- The client configures the type and ordering of Core and Decorator objects.

Thumb Rules

- Adapter provides a different interface to its subject. Proxy provides the same interface. Decorator provides an enhanced interface.

- Adapter changes an object’s interface, Decorator enhances an object’s responsibilities. Decorator is thus more transparent to the client. As a consequence, Decorator supports recursive composition, which isn’t possible with pure Adapters.

- Composite and Decorator have similar structure diagrams, reflecting the fact that both rely on recursive composition to organize an open-ended number of objects.

- A Decorator can be viewed as a degenerate Composite with only one component. However, a Decorator adds additional responsibilities - it isn’t intended for object aggregation.

- Decorator is designed to let you add responsibilities to objects without subclassing. Composite’s focus is not on embellishment but on representation. These intents are distinct but complementary. Consequently, Composite and Decorator are often used in concert.

- Composite could use Chain of Responsibility to let components access global properties through their parent. It could also use Decorator to override these properties on parts of the composition.

- Decorator and Proxy have different purposes but similar structures. Both describe how to provide a level of indirection to another object, and the implementations keep a reference to the object to which they forward requests.

- Decorator lets you change the skin of an object. Strategy lets you change the guts.

Code

#include<iostream.h>

class I {

public:

virtual ~I(){}

virtual void do_it() = 0;

};

class A: public I {

public:

~A() {

cout << "A dtor" << '\n';

}

/*virtual*/

void do_it() {

cout << 'A';

}

};

class D: public I {

public:

D(I *inner) {

m_wrappee = inner;

}

~D() {

delete m_wrappee;

}

/*virtual*/

void do_it() {

m_wrappee->do_it();

}

private:

I *m_wrappee;

};

class X: public D {

public:

X(I *core): D(core){}

~X() {

cout << "X dtor" << " ";

}

/*virtual*/

void do_it() {

D::do_it();

cout << 'X';

}

};

class Y: public D {

public:

Y(I *core): D(core){}

~Y() {

cout << "Y dtor" << " ";

}

/*virtual*/

void do_it() {

D::do_it();

cout << 'Y';

}

};

class Z: public D {

public:

Z(I *core): D(core){}

~Z() {

cout << "Z dtor" << " ";

}

/*virtual*/

void do_it() {

D::do_it();

cout << 'Z';

}

};

int main() {

I *anX = new X(new A);

I *anXY = new Y(new X(new A));

I *anXYZ = new Z(new Y(new X(new A)));

anX->do_it();

cout << '\n';

anXY->do_it();

cout << '\n';

anXYZ->do_it();

cout << '\n';

delete anX;

delete anXY;

delete anXYZ;

system("PAUSE");

}

AX

AXY

AXYZ

X dtor A dtor

Y dtor X dtor A dtor

Z dtor Y dtor X dtor A dtor