1 核心定义装饰模式是一种结构型设计模式它允许在不改变现有对象结构的情况下动态地给该对象添加一些额外的职责。装饰模式通过创建包装对象装饰器来包裹真实对象提供了比继承更有弹性的替代方案。2 核心思想继承的替代方案提供比继承更灵活的扩展方式开闭原则对扩展开放对修改封闭动态性可以在运行时动态添加或撤销功能透明性装饰对象和真实对象具有相同的接口3 结构组成Component组件接口定义对象接口可动态添加职责ConcreteComponent具体组件实现组件接口的具体对象Decorator装饰器抽象类持有一个组件引用实现组件接口ConcreteDecorator具体装饰器向组件添加具体职责4 应用场景举例以咖啡订单系统为例假设我们需要计算不同咖啡饮品的价格和描述基础咖啡浓缩咖啡、美式咖啡配料牛奶、摩卡、奶油等顾客可以自由组合基础咖啡和配料5 UML6 c 代码实现#includeiostream#includestringusingnamespacestd;// 抽象组件咖啡接口classCoffee{public:virtual~Coffee()default;virtualstringgetDescription()const0;virtualdoublecost()const0;};// 具体组件浓缩咖啡classEspresso:publicCoffee{public:stringgetDescription()constoverride{return浓缩咖啡;}doublecost()constoverride{return25.0;// 基础价格25元}};// 具体组件美式咖啡classAmericano:publicCoffee{public:stringgetDescription()constoverride{return美式咖啡;}doublecost()constoverride{return20.0;// 基础价格20元}};// 抽象装饰器配料装饰器classCoffeeDecorator:publicCoffee{protected:Coffee*coffee;// 持有的被装饰对象public:CoffeeDecorator(Coffee*c):coffee(c){}stringgetDescription()constoverride{returncoffee-getDescription();}doublecost()constoverride{returncoffee-cost();}virtual~CoffeeDecorator(){deletecoffee;}};// 具体装饰器牛奶classMilk:publicCoffeeDecorator{public:Milk(Coffee*c):CoffeeDecorator(c){}stringgetDescription()constoverride{returncoffee-getDescription() 牛奶;}doublecost()constoverride{returncoffee-cost()5.0;// 牛奶加5元}};// 具体装饰器摩卡classMocha:publicCoffeeDecorator{public:Mocha(Coffee*c):CoffeeDecorator(c){}stringgetDescription()constoverride{returncoffee-getDescription() 摩卡;}doublecost()constoverride{returncoffee-cost()8.0;// 摩卡加8元}};// 具体装饰器奶油classWhip:publicCoffeeDecorator{public:Whip(Coffee*c):CoffeeDecorator(c){}stringgetDescription()constoverride{returncoffee-getDescription() 奶油;}doublecost()constoverride{returncoffee-cost()6.0;// 奶油加6元}};// 客户端代码intmain(){// 点一杯浓缩咖啡加牛奶和摩卡Coffee*coffeenewEspresso();coffeenewMilk(coffee);coffeenewMocha(coffee);cout订单: coffee-getDescription()endl;cout价格: coffee-cost()元endl;deletecoffee;return0;}7 总结如果不使用装饰模式可能会有以下几种实现方式方式1使用继承每个组合创建一个子类// 问题类爆炸classEspressoWithMilk:publicEspresso{/* ... */};classEspressoWithMocha:publicEspresso{/* ... */};classEspressoWithMilkAndMocha:publicEspresso{/* ... */};classAmericanoWithMilk:publicAmericano{/* ... */};// ... 需要为每种组合创建类如果有3种基础咖啡和5种配料就需要3*2^596个类方式2使用属性标志classCoffee{private:boolhasMilk;boolhasMocha;boolhasWhip;// ... 需要为每种配料添加标志public:doublecost(){doubletotalbasePrice;if(hasMilk)total5;if(hasMocha)total8;if(hasWhip)total6;returntotal;}};主要问题1 违反开闭原则每次添加新的配料都需要修改Coffee类2 代码臃肿类的职责过重包含所有配料的逻辑3 维护困难添加新配料需要修改现有代码容易引入bug4 灵活性差无法动态改变配料组合配料的组合在编译时就固定了5 代码重复如果配料的价格计算逻辑复杂不同咖啡类中会有重复代码装饰模式的优势1 灵活扩展可以在不修改现有代码的情况下添加新功能2 组合自由可以在运行时自由组合不同的装饰器3 符合单一职责每个装饰器只负责一个特定的功能4 避免类爆炸不需要为每个组合创建新的子类5 可撤销可以动态地添加或移除装饰器装饰模式通过将复杂的功能分解为简单的小功能并通过组合的方式实现复杂功能是一种非常灵活的代码组织方式。