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

GoF decorator pattern using static polymorphism (templates) in c++

本文关键字:静态 多态性 模板 c++ 模式 GoF      更新时间:2023-10-16

decorator模式是一种众所周知的模式,用于在不影响同类其他对象功能的情况下扩展对象的功能。如何在继承较少的情况下使用此模式(使用模板)?

基本上,多态装饰器的抽象接口变成了一个隐式定义的概念,并且嵌套了类型。例如:

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;
};

您可能想使用对象生成器习惯用法来简化合成:

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

由于没有通用类型来存储装饰对象,因此需要使用某种类型推断。例如:

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

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

addSugar(addCream(BasicCoffee())).print();

如果不显式包装正在装饰的东西的所有公共方法,就无法做到这一点。举个例子:

#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();
}

如果在decorator中删除bar的(无用的)装饰,编译将失败。抛开这个复杂因素不谈,这是完全可行的。。。除了所有接受可适配实体的函数现在也必须被模板化之外。所以最后我不建议走这条路。

这种方法的另一个缺点是,即使你只修饰引用,也必须为你最终使用的所有模板专门化生成代码,因为如果没有vtable,编译器将无法统一处理具有相同名称的不同类的方法;如果你让你的类从一个声明这些方法为虚拟的父类继承,那么使用模板就没有什么好处了——你可能会获得性能,但也可能会失去它,因为更多的代码会在缓存中膨胀。