装饰者模式定义

动态地将责任附加到对象上,若要扩展功能,装饰者模式提供了比继承更具有弹性的替代方案。

主要包含四部分:

抽象组件,抽象装饰者,具体组件,具体装饰者

实例:咖啡点餐机实现

  1. #include "bits/stdc++.h"
  2. using namespace std;
  3. enum SIZE {
  4. BIG = 0, MID = 1, SMALL = 2
  5. };
  6. // 饮料类
  7. class Beverage {
  8. public:
  9. virtual string getDescription() {
  10. return description;
  11. }
  12. virtual double cost() = 0;;
  13. virtual SIZE getSize() = 0;
  14. private:
  15. string description = "Unknown Beverage";
  16. SIZE cup_size{};
  17. };
  18. // 开始制作第一种饮料,比如浓缩咖啡Espresso
  19. class Espresso : public Beverage {
  20. public:
  21. ~Espresso() = default;
  22. explicit Espresso(SIZE size) {
  23. description = "Espresso";
  24. cup_size = size;
  25. }
  26. string getDescription() override {
  27. return description;
  28. }
  29. double cost() override {
  30. return 1.99;
  31. }
  32. void setSize(SIZE i) {//设置咖啡杯的大小
  33. cup_size = i;
  34. }
  35. SIZE getSize() override {//获得咖啡杯的大小
  36. return cup_size;
  37. }
  38. private:
  39. string description;
  40. SIZE cup_size;
  41. };
  42. // 第二种饮料 HouseBlend
  43. class HouseBlend : public Beverage {
  44. public:
  45. ~HouseBlend() = default;
  46. explicit HouseBlend(SIZE size) {
  47. description = "House Blend Coffee";
  48. cup_size = size;
  49. }
  50. string getDescription() override {
  51. return description;
  52. }
  53. double cost() override {
  54. return 0.89;
  55. }
  56. void setSize(SIZE i) {//设置咖啡杯的大小
  57. cup_size = i;
  58. }
  59. SIZE getSize() override {//获得咖啡杯的大小
  60. return cup_size;
  61. }
  62. private:
  63. string description;
  64. SIZE cup_size;
  65. };
  66. // 由于装饰者和被装饰者必须是一样的类型,也就是具有共同的超类,因此抽象装饰者继承自抽象组件,以达成类型匹配。
  67. // 抽象装饰者,调料,
  68. class Condiment : public Beverage {
  69. public:
  70. virtual string getDescription() = 0;
  71. };
  72. // 现在有了抽象组件Beverage 和具体组件Espresso等,也有了抽象装饰者Condiment,现在实现具体装饰者
  73. //摩卡
  74. class Mocha : public Condiment {
  75. public:
  76. ~Mocha() = default;
  77. explicit Mocha(Beverage *temp) {
  78. this->coffee = temp;
  79. }
  80. string getDescription() override {
  81. return coffee->getDescription() + ", Mocha";
  82. }
  83. SIZE getSize() override {
  84. return coffee->getSize();
  85. }
  86. double cost() override {//根据咖啡杯的大小决定加摩卡的价格
  87. double cost = coffee->cost();
  88. switch (getSize()) {
  89. case SMALL:
  90. cost += 0.20;
  91. break;
  92. case MID:
  93. cost += 0.25;
  94. break;
  95. case BIG:
  96. cost += 0.30;
  97. break;
  98. default:
  99. cout << "There is not this SIZE" << endl;
  100. }
  101. return cost;
  102. }
  103. private:
  104. Beverage *coffee;
  105. };
  106. //奶泡
  107. class Whip : public Condiment {
  108. public:
  109. ~Whip() = default;
  110. explicit Whip(Beverage *temp) {
  111. this->coffee = temp;
  112. }
  113. string getDescription() override {
  114. return coffee->getDescription() + ", Soy";
  115. }
  116. SIZE getSize() override {
  117. return coffee->getSize();
  118. }
  119. double cost() override {
  120. double cost = coffee->cost();
  121. switch (getSize()) {
  122. case SMALL:
  123. cost += 0.10;
  124. break;
  125. case MID:
  126. cost += 0.15;
  127. break;
  128. case BIG:
  129. cost += 0.20;
  130. break;
  131. default:
  132. cout << "There is not this SIZE" << endl;
  133. }
  134. return cost;
  135. }
  136. private:
  137. Beverage *coffee;
  138. };
  139. int main() {
  140. cout<<">>>>>>>>>>>>>> Decorator Mode>>>>>>>>>>>>>";
  141. // 大杯浓缩咖啡
  142. Beverage *beverage1 = new Espresso(BIG);
  143. cout << beverage1->getDescription() << " $" << beverage1->cost() << endl;
  144. // 中杯 星巴克+ 两份摩卡 + 奶泡
  145. Beverage *beverage2 = new HouseBlend(MID);
  146. beverage2 = new Mocha(beverage2);
  147. beverage2 = new Mocha(beverage2);
  148. beverage2 = new Whip(beverage2);
  149. cout << beverage2->getDescription() << " $" << beverage2->cost() << endl;
  150. return 0;
  151. }

总结

1.装饰者和被装饰者必须是同一类型,这是装饰者模式的关键,在这里是利用继承达到“类型匹配”,而非继承行为。

2.装饰者和被装饰者进行组合时,就在装饰者中加入了新的行为,行为不是来自继而是来自组合。

3.依赖继承的行为,在编译时静态决定。利用组合,可以把装饰者混合使用,并且是在运行时决定行为。

装饰者模式 - 图1