装饰者模式
1.动态地将责任附加到对象上,扩展功能,比继承更有弹性。
2.代码
C++
1 //decorate c++ 2 #include <iostream> 3 #include <string> 4 using namespace std; 5 6 //基类 饮料 7 class Beverage{ 8 public: 9 Beverage(string s): description(s){} 10 virtual string getDescription(){ //配料需覆盖,饮料不用 11 return description; 12 } 13 virtual double cost() = 0; 14 private: 15 string description; 16 }; 17 18 //子类 饮料:浓咖啡 19 class Espresso : public Beverage{ 20 public: 21 Espresso() : Beverage("Espresso"){} //不能在子类初始化列表初始化父类成员 22 double cost(){ 23 return 1.99; 24 } 25 }; 26 27 //子类 饮料:混合 28 class HouseBlend : public Beverage{ 29 public: 30 HouseBlend() : Beverage("House Blend coffee"){} 31 double cost(){ 32 return 0.89; 33 } 34 }; 35 36 //配料 37 class CondimentDecorator : public Beverage{ 38 public: 39 CondimentDecorator(string s): Beverage(s){} 40 }; 41 42 //配料:摩卡 43 class Mocha : public CondimentDecorator{ 44 public: 45 Mocha(Beverage* beverage) : m_pbeverage(beverage),CondimentDecorator("Mocha"){} 46 string getDescription(){ 47 return m_pbeverage->getDescription() + ",Mocha"; 48 } 49 double cost(){ 50 return .20 + m_pbeverage->cost(); 51 } 52 private: 53 Beverage* m_pbeverage; 54 }; 55 56 //配料:鲜奶油 57 class Whip : public CondimentDecorator{ 58 public: 59 Whip(Beverage* beverage) : m_pbeverage(beverage),CondimentDecorator("Whip"){} 60 string getDescription(){ 61 return m_pbeverage->getDescription() + ",Whip"; 62 } 63 double cost(){ 64 return .30 + m_pbeverage->cost(); 65 } 66 private: 67 Beverage* m_pbeverage; 68 }; 69 70 // 71 int main(){ 72 //beverage*1 73 Beverage* beverage_1 = new Espresso(); 74 cout<<beverage_1->getDescription()<<" $"<<beverage_1->cost()<<endl; 75 76 //Mocha*2 Whip*1 77 Beverage* beverage_2 = new Espresso(); 78 beverage_2 = new Mocha(beverage_2); 79 beverage_2 = new Mocha(beverage_2); 80 beverage_2 = new Whip(beverage_2); 81 cout<<beverage_2->getDescription()<<" $"<<beverage_2->cost()<<endl; 82 83 return 0; 84 }
Java
1 //decorate java 2 //base class 3 abstract class Beverage{ 4 String description = "Unknown Beverage"; 5 public String getDescription(){ 6 return description; 7 } 8 public abstract double cost(); 9 } 10 abstract class CondimentDecorator extends Beverage{ 11 public abstract String getDescription(); 12 } 13 14 //Espresso 15 class Espresso extends Beverage{ 16 public Espresso(){ 17 description = "Espresso"; 18 } 19 public double cost(){ 20 return 1.99; 21 } 22 } 23 24 //HouseBlend 25 class HouseBlend extends Beverage{ 26 public HouseBlend(){ 27 description = "House Blend coffee"; 28 } 29 public double cost(){ 30 return 0.89; 31 } 32 } 33 //Mocha 34 class Mocha extends CondimentDecorator{ 35 Beverage beverage; 36 public Mocha(Beverage beverage){ 37 this.beverage = beverage; 38 } 39 public String getDescription(){ 40 return beverage.getDescription() + ",Mocha"; 41 } 42 public double cost(){ 43 return .20 + beverage.cost(); 44 } 45 } 46 47 //Whip 48 class Whip extends CondimentDecorator{ 49 Beverage beverage; 50 public Whip(Beverage beverage){ 51 this.beverage = beverage; 52 } 53 public String getDescription(){ 54 return beverage.getDescription() + ",Whip"; 55 } 56 public double cost(){ 57 return .30 + beverage.cost(); 58 } 59 } 60 //main 61 public class StarbuzzCoffee{ 62 public static void main(String[] args){ 63 //a beverage 64 Beverage beverage = new Espresso(); 65 System.out.println(beverage.getDescription() + " $" + beverage.cost()); 66 67 //Mocha*2 Whip*1 68 Beverage beverage2 = new Espresso(); 69 beverage2 = new Mocha(beverage2); 70 beverage2 = new Mocha(beverage2); 71 beverage2 = new Whip(beverage2); 72 System.out.println(beverage2.getDescription() + " $" + beverage2.cost()); 73 } 74 }
3. 杂记:
(1)利用继承设计子类的行为是在编译时静态决定的
利用组合扩展对象的行为,动态的
组合维护,添加新功能,无须更改已存在代码,bug引入风险低
(2)类应该对扩展开放,对修改关闭
每个部分都遵守:没必要,增加复杂度;通常集中在最有可能改变的地方
(3)应对继承滥用设计
(4)装饰和被装饰者 有相同基类,利用继承达到类型匹配,而不是利用继承获得 行为
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通