C++装饰器模式多层装饰调用的执行逻辑问题
装饰器模式问题解答
现有实现的运行结果
你的判断是对的,按照当前给出的代码实现,最终调用a->imp()时,c的值只会是最外层A类实例自身的成员c加1,结果为1,完全不会触发其他装饰层和Base类的逻辑,问题出在两个核心设计错误:
- 所有具体装饰类(A/B/C)重写
imp()方法后,没有调用内部持有的被装饰对象的imp(),方法执行完自身逻辑就直接返回,调用链根本不会向内层传递 - 所有继承自
abs的类实例都各自持有独立的c成员变量,不是全局共享的,就算后续补上了内层调用,各层修改的也是自己实例的c,外层对象拿不到内层的修改结果。
正确实现方案
要实现只调用一次最外层imp(),就按B→A→C→A的装饰顺序执行所有加值逻辑,最终得到c=0+2+1+3+1=7的结果,只需要做两处修正:
- 每个具体装饰器的
imp()方法中,根据需要的执行顺序,在合适位置调用内部被装饰对象的imp()方法,把调用沿着装饰链逐层传递下去 - 把需要累加修改的
c变量放到共享位置,不要让每个对象各自持有独立副本。最符合装饰器模式设计的做法是把c放在最底层的Base实例中,所有装饰层通过接口访问同一个c实例,避免修改分散。
修正后的可运行代码
#include <iostream> class abs { public: virtual void imp() = 0; virtual int& getC() = 0; virtual ~abs() = default; }; // 基础组件,持有唯一的共享c变量 class Base : public abs { private: int c; public: Base() : c(0) {} int& getC() override { return c; } void imp() override {} }; // 装饰器基类 class Decorator : public abs { protected: abs* wrapped; public: Decorator(abs* obj) : wrapped(obj) {} void imp() override { if (wrapped) wrapped->imp(); } int& getC() override { return wrapped->getC(); } ~Decorator() override { delete wrapped; } }; // 加1的装饰器A class A : public Decorator { public: A(abs* obj) : Decorator(obj) {} void imp() override { // 先调用内层逻辑,执行顺序就会和装饰包装顺序一致:从最内层往最外层执行 Decorator::imp(); getC() += 1; } }; // 加2的装饰器B class B : public Decorator { public: B(abs* obj) : Decorator(obj) {} void imp() override { Decorator::imp(); getC() += 2; } }; // 加3的装饰器C class C : public Decorator { public: C(abs* obj) : Decorator(obj) {} void imp() override { Decorator::imp(); getC() += 3; } }; int main() { abs* obj = new Base; // 按B、A、C、A的顺序包装装饰 obj = new B(obj); obj = new A(obj); obj = new C(obj); obj = new A(obj); obj->imp(); std::cout << "c的最终值:" << obj->getC() << std::endl; // 输出7,正好是0+2+1+3+1的结果 delete obj; return 0; }
补充说明
装饰器的执行顺序不是固定的:如果你把自身逻辑写在调用内层imp()之前,执行顺序就是从最外层往最内层跑;如果像示例代码这样先调用内层imp()再写自身逻辑,执行顺序就是从最内层往最外层跑,和你包装装饰器的顺序完全一致,可以根据业务需求灵活调整。
内容的提问来源于stack exchange,提问作者Aaditya Yadav
相关产品推荐
相关产品推荐

