• Articles
  • Decorating objects with templates
Published by
Jun 25, 2011 (last update: Jun 25, 2011)

Decorating objects with templates

Score: 3.5/5 (64 votes)
*****
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.