目录核心思想参与者优缺点优点缺点使用场景实战动态地给一个对象添加一些额外的职责。就增加的功能来说装饰器模式相比生成子类更为灵活。核心思想有时候需要给某个对象而不是整个类添加一些功能使用继承也可以但是子类行为是静态的而用户不能动态的控制如果希望在无需修改代码且运行时为对象新增额外的行为可以使用装饰器模式。装饰器的核心在于装饰器与被装饰的对象实现同一个接口因此装饰器可以被当成原对象使用客户端无感知装饰器可以包装成另一个装饰器对照用继承做同样的事情为什么不行功能组合是乘法——带时间戳带过滤带其他…每种组合一个子类(2^n), 装饰器只需要N个类运行期自由拼装。与 Bridge模式的维度爆炸相似只是维度从 “平台/编码” 换成了 “功能叠加”参与者角色本例对应职责抽象组件 ComponentLogger统一接口定义对象接口——装饰前后的同一张脸具体组件 ConcreteComponentConsoleLogger被装饰的原对象抽象装饰器 DecoratorLoggerDecorator中间基类持有 inner默认纯转发具体装饰器 ConcreteDecoratorTimestampDecorator/UpperDecorator/CountDecorator前置/变换/观察三种形态举例代码classLogger{public:virtual~Logger()default;virtualvoidlog(conststd::stringmsg)0;};// Concrete component classConsoleLogger:publicLogger{public:voidlog(conststd::stringmsg)override{std::printf(console %s\n,msg.c_str());}};// Decorator middle base: IS a Logger AND HOLDS a Logger classLoggerDecorator:publicLogger{public:explicitLoggerDecorator(std::unique_ptrLoggerinner):inner_(std::move(inner)){}protected:std::unique_ptrLoggerinner_;// owns the wrapped object (onion layer)};classTimestampDecorator:publicLoggerDecorator{public:usingLoggerDecorator::LoggerDecorator;voidlog(conststd::stringmsg)override{inner_-log([12:00:00] msg);// prepend: pre-processing}};classUpperDecorator:publicLoggerDecorator{public:usingLoggerDecorator::LoggerDecorator;voidlog(conststd::stringmsg)override{inner_-log(to_upper(msg));// transform the payload}private:staticstd::stringto_upper(conststd::strings){std::string outs;for(charc:out){if(cacz){cstatic_castchar(c-aA);}}returnout;}};classCountDecorator:publicLoggerDecorator{public:usingLoggerDecorator::LoggerDecorator;voidlog(conststd::stringmsg)override{count_;// observe forward untouchedinner_-log(msg);}intcount()const{returncount_;}// beyond the Logger interface!private:intcount_0;};intmain(){// The client holds ONE Logger and is unaware of the layering:// Count( Timestamp( Upper( Console ) ) ) — an onion.std::unique_ptrLoggerloggerstd::make_uniqueCountDecorator(std::make_uniqueTimestampDecorator(std::make_uniqueUpperDecorator(std::make_uniqueConsoleLogger())));logger-log(robot state: running);logger-log(battery low);// Reading count() needs the concrete type — the classic// half-transparent decorator problem: the extra method is invisible// through the Component interface, so a downcast is required.constauto*counterdynamic_castconstCountDecorator*(logger.get());std::printf(total messages: %d\n,counter?counter-count():-1);return0;}继承功能组合爆炸装饰器加一层功能1类三种功能各写一遍继承组合子类装饰器2 层功能时2² 4 叶1 组件 2 装饰器加计数© 后2³ 8 叶4 类1 类CountDecorator计数逻辑要写几遍4 遍C/CT/CU/CTU 各一份1 遍时间戳逻辑累计4 遍且继续膨胀1 遍运行期拆装/换序不可能组合在类型里焊死换个包装顺序T(U(x))≠U(T(x))再加第 4 层功能再加 8 个类再加 1 个类优缺点优点运行期动态叠加/重排/移除 职责避免功能组合的子类爆炸每侧单一职责可独立测试原类零改动缺点多层调用开销N次虚跳与调试可读性装饰顺序即语义顺序拼装代码要小心小系统直接继承更简洁使用场景动态可配置的横切叠加如日志装饰IO流包装缓存层限流/重试/超时(BT的DecatorNode全家)权限校验层不能修改原类时的行为增强一句话装饰器解决“功能的多选可叠加”与“继承的子类单一功能”之间的错配——用同一接口把职责组合从编译期的类型树改写成运行期的对象洋葱代价是每调用一次要穿过整只洋葱。实战BT.CPP的DecoratorNode行为树的Retry/Inverter/Timeout家族就是装饰器与被装饰节点同一接口TreeNode、恰好一个子、修饰tick()语义后转发classDecoratorNode:publicTreeNode{// 同接口public:DecoratorNode(std::string name,std::unique_ptrTreeNodechild):TreeNode(std::move(name)),child_(std::move(child)){}protected:std::unique_ptrTreeNodechild_;// 单子独占};classInverterNode:publicDecoratorNode{// 修饰取反NodeStatustick()override{switch(child_-execute_tick()){casekSuccess:returnkFailure;casekFailure:returnkSuccess;default:returnkRunning;}}};