The decorator pattern is explained quite well on Wikipedia, but the principle is to have a common base, some implementations of it, and the desire to modify the functionallity of the implementations without modifying the implementations themselves.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
struct CommonBase
{
virtual void func() =0;
};
struct Derived1 : public CommonBase
{
virtual void func() {
//implementation
}
void d1() {}
};
struct Derived2 : public CommonBase
{
virtual void func() {
//different implementation
}
void d2() {}
};
|
Let us say we wanted every call to
func to print a message. The decorator pattern says we can do this as follows
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
struct Decorator : public CommonBase
{
CommonBase *b;
Decorator(CommonBase *b) : b(b) {}
virtual void func() {
std::cout << "Message" << std::endl;
b->func();
}
};
CommonBase *cb2 = new Decorator(new Derived2);
cb2->func();
CommonBase *cb1 = new Decorator(new Derived1);
cb1->func();
|
This is great. However, there is a downside, because we can only work through
CommonBase pointers, we have now lost the ability to call
d1 and
d2 without downcasting.
There is however another way. Consider the following template
1 2 3 4 5 6 7 8 9 10 11
|
template<class T>
struct DifferentDecorator : public T
{
virtual void func() {
std::cout << "Message" << std::endl;
T::func();
}
}
Derived1 *d1 = new DifferentDecorator<Derived1>;
Derived2 *d2 = new DifferentDecorator<Derived2>;
|
Now I have a single decorator that will work on any class providing
func, so I don't need to duplicate code. But I can now use the pointer to the derived class to call whatever methods I want, so am no longer restricted to what is in
CommonBase.
Passing constructors to the derived classes can be done using templatized constructors in the
BetterDecorator class.