GoF decorator template using static polymorphism (templates) in C ++

The decorator pattern is a well-known and used pattern for expanding the functionality of an object without affecting the functionality of other objects of the same class. How can I use this template with less inheritance (using templates)?

+6
source share
2 answers

Basically, the abstract interface from a polymorphic decorator becomes an implicitly defined concept, and you insert types. For instance:

struct BasicCoffee { void print() {std::cout << "Coffee!\n";} }; template <class T> struct CreamDecorator { CreamDecorator(T x) : mNested(x) {} void print() {mNested.print(); std::cout << "..with cream!\n";} T mNested; }; template <class T> struct SugarDecorator { SugarDecorator(T x) : mNested(x) {} void print() {mNested.print(); std::cout << "..with sugar!\n";} T mNested; }; 

You probably want to use the identifier of the object generator to simplify the layout:

 template <class T> CreamDecorator<T> addCream(T x) {return CreamDecorator<T>(x);} template <class T> SugarDecorator<T> addSugar(T x) {return SugarDecorator<T>(x);} 

Since you do not have a general type for storing decorated objects, you need to use some type of output. For instance:

 auto myCoffee = addSugar(addCream(BasicCoffee())); myCoffee.print(); 

Alternatively, use the value that you get from object generators like rvalue (this can be useful if you are stuck with erasure like C ++ 03, it can also help!):

 addSugar(addCream(BasicCoffee())).print(); 
+7
source

You cannot do this without explicitly wrapping all publicly available methods of what you decorate. Consider an example:

 #include <iostream> using namespace std; class Test { public: void foo() { cout << "Foo" << endl; } void bar() { cout << "Bar" << endl; } }; template <typename T> class FooDecorator { public: explicit FooDecorator(T &t) : t(t) {} void foo() { cout << "Baz "; t.foo(); } void bar() { t.bar(); } private: T &t; }; template <typename T> class BarDecorator { public: explicit BarDecorator(T &t) : t(t) {} void foo() { t.foo(); } void bar() { cout << "Baez "; t.bar(); } private: T &t; }; int main() { Test test; BarDecorator<FooDecorator<Test> > bd(FooDecorator<Test>(test)); bd.foo(); bd.bar(); } 

If you remove the (useless) bar decoration in the decorator, compilation will fail. This complication aside, it is completely doable ... except that all functions that accept the entity being decorated must now also be templated. Therefore, in the end, I do not recommend going along this road.

Another drawback of this approach is that even if you only decorate links, the code must be generated for all specialized templates that you end up using, because without a vtable, the compiler will not process methods of different classes using the same name uniformly ; and if you inherit your classes from one parent who declares these methods as virtual, the use of templates is of little use - you can increase performance, but you can just lose it because more code inflates the cache.

+1
source

All Articles