在c ++中使用静态多态(模板)的GoF装饰器模式

Dan*_*per 7 c++ templates decorator

装饰器模式是众所周知的用于扩展对象功能的模式,而不会影响同一类的其他对象的功能.如何使用此模式并减少继承(使用模板)?

ltj*_*jax 9

基本上,多态装饰器的抽象接口成为隐式定义的概念,您可以嵌套类型.例如:

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;
};
Run Code Online (Sandbox Code Playgroud)

您可能希望使用对象生成器惯用法来使合成更容易:

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

template <class T>
SugarDecorator<T> addSugar(T x) {return SugarDecorator<T>(x);}
Run Code Online (Sandbox Code Playgroud)

由于您没有用于存储装饰对象的公共类型,因此需要使用某种类型推断.例如:

auto myCoffee = addSugar(addCream(BasicCoffee()));
myCoffee.print();
Run Code Online (Sandbox Code Playgroud)

或者,使用从对象生成器获得的值作为右值(如果您遇到C++ 03,这可能很有用 - 类型擦除也可以帮助!):

addSugar(addCream(BasicCoffee())).print();
Run Code Online (Sandbox Code Playgroud)

  • 不,这样你就可以通过使用或不使用ref来实例化模板来明确说明你是想要副本还是引用.例如:CreamDecorator <T> vs CreamDecorator <T const&>或CreamDecorator <T&>,甚至使用std :: ref/cref和reference_wrapper.不使用引用允许更容易的组合 - 而C++ 11移动也使这个效率更高! (3认同)