🎭 装饰器模式 (Decorator Pattern)
🎯 模式概述
装饰器模式是一种结构型设计模式,它允许向一个现有的对象添加新的功能,同时又不改变其结构。这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
装饰器模式就像现实生活中给房子装修一样,我们可以给基础的房子添加各种装饰:贴墙纸、安装吊灯、铺地毯等,每一种装饰都增加了房子的功能和美观性,但房子的基本结构没有改变。
🔍 核心思想
装饰器模式通过将对象放入包含行为的特殊封装器中来为原对象绑定新的行为。装饰器与目标对象具有相同的接口,因此可以向客户端传递任何装饰器而不是原始对象。
📊 UML类图结构
装饰器模式 UML
┌─────────────────┐
│ Component │
│ <<abstract>> │
│ │
│ + operation() │
└─────────────────┘
△
│
┌────────────┼────────────┐
│ │
┌─────────────────┐ ┌─────────────────┐
│ConcreteComponent│ │ Decorator │
│ │ │ <<abstract>> │
│ + operation() │ │ │
└─────────────────┘ │ - component: │
│ Component* │
│ │
│ + operation() │
└─────────────────┘
△
│
┌────────────┼────────────┐
│ │
┌─────────────────┐ ┌─────────────────┐
│ConcreteDecoratorA│ │ConcreteDecoratorB│
│ │ │ │
│ + operation() │ │ + operation() │
│ + addedBehavior()│ │ + anotherBehavior()│
└─────────────────┘ └─────────────────┘
┌─────────────────┐
│ Client │ ─────────────► Component
│ │
│ + doSomething() │
└─────────────────┘
🔍 关键点:装饰器持有Component引用,可以递归包装形成装饰链
装饰器链结构示意
Client
│
▼
┌─────────────────┐ wraps ┌─────────────────┐ wraps ┌─────────────────┐
│ ConcreteDecoratorA│ ────────► │ ConcreteDecoratorB│ ────────► │ConcreteComponent│
│ │ │ │ │ │
│ + operation() │ │ + operation() │ │ + operation() │
│ { │ │ { │ │ │
│ // 添加行为A │ │ // 添加行为B │ └─────────────────┘
│ component. │ │ component. │
│ operation() │ │ operation() │
│ } │ │ } │
└─────────────────┘ └─────────────────┘
🔍 装饰器链:每个装饰器都可以包装另一个装饰器或基础组件
🤔 为什么需要装饰器模式?
📊 问题场景对比
| 问题场景 | 传统继承方式 | 装饰器模式 |
|---|---|---|
| 🎨 功能组合 | 需要大量子类 | 动态组合装饰器 |
| 🔧 运行时扩展 | 编译时确定功能 | 运行时动态添加 |
| 📦 避免类爆炸 | 每种组合一个类 | 少量装饰器灵活组合 |
| ♻️ 功能复用 | 重复代码 | 装饰器可重复使用 |
💡 问题演示
// ❌ 传统继承方式的问题
class Coffee {
public:
virtual double cost() = 0;
virtual std::string description() = 0;
};
class SimpleCoffee : public Coffee {
public:
double cost() override {
return 5.0; }
std::string description() override {
return "Simple Coffee"; }
};
// 如果要添加牛奶、糖、奶油等,传统方式需要大量子类:
class CoffeeWithMilk : public Coffee {
/*...*/ };
class CoffeeWithSugar : public Coffee {
/*...*/ };
class CoffeeWithMilkAndSugar : public Coffee {
/*...*/ };
class CoffeeWithMilkAndSugarAndCream : public Coffee {
/*...*/ };
// ... 组合爆炸!
// 问题:每种组合都需要一个新类,类的数量会指数级增长
🎭 装饰器模式实现方式
1️⃣ 经典装饰器模式实现
让我们用咖啡店的例子来演示装饰器模式:
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include <iomanip>
// 抽象组件:饮料基类
class Beverage {
public:
virtual ~Beverage() = default;
virtual std::string getDescription() const = 0;
virtual double cost() const = 0;
virtual std::string getSize() const {
return "中杯"; }
virtual int getCalories() const = 0;
virtual void showDetails() const {
std::cout << "🍺 " << getDescription() << std::endl;
std::cout << "├─ 规格: " << getSize() << std::endl;
std::cout << "├─ 价格: ¥" << std::fixed << std::setprecision(2) << cost() << std::endl;
std::cout << "└─ 热量: " << getCalories() << " 卡路里" << std::endl;
}
};
// 具体组件:基础咖啡
class Coffee : public Beverage {
private:
std::string size;
std::string roastLevel;
public:
explicit Coffee(const std::string& sz = "中杯", const std::string& roast = "中度烘焙")
: size(sz), roastLevel(roast) {
std::cout << "☕ 制作基础咖啡: " << size << " " << roast << std::endl;
}
std::string getDescription() const override {
return roastLevel + "咖啡";
}
double cost() const override {
if (size == "小杯") return 12.0;
else if (size == "中杯") return 15.0;
else if (size == "大杯") return 18.0;
else return 15.0;
}
std::string getSize() const override {
return size;
}
int getCalories() const override {
return 5; // 黑咖啡热量很低
}
};
// 具体组件:茶
class Tea : public Beverage {
private:
std::string teaType;
std::string size;
public:
explicit Tea(const std::string& type = "绿茶", const std::string& sz = "中杯")
: teaType(type), size(sz) {
std::cout << "🍵 冲泡茶饮: " << size << " " << teaType << std::endl;
}
std::string getDescription() const override {
return teaType;
}
double cost() const override {
double basePrice = 10.0;
if (teaType == "龙井茶" || teaType == "铁观音") basePrice = 20.0;
if (size == "小杯") return basePrice * 0.8;
else if (size == "中杯") return basePrice;
else if (size == "大杯") return basePrice * 1.3;
else return basePrice;
}
std::string getSize() const override {
return size;
}
int getCalories() const override {
return 2; // 纯茶热量极低
}
};
// 抽象装饰器
class BeverageDecorator : public Beverage {
protected:
std::unique_ptr<Beverage> beverage;
public:
explicit BeverageDecorator(std::unique_ptr<Beverage> bev)
: beverage(std::move(bev)) {
}
std::string getDescription() const override {
return beverage->getDescription();
}
double cost() const override {
return beverage->cost();
}
std::string getSize() const override {
return beverage->getSize();
}
int getCalories() const override {
return beverage->getCalories();
}
};
// 具体装饰器:牛奶
class MilkDecorator : public BeverageDecorator {
private:
std::string milkType;
public:
explicit MilkDecorator(std::unique_ptr<Beverage> bev, const std::string& type = "全脂牛奶")
: BeverageDecorator(std::move(bev)), milkType(type) {
std::cout << "🥛 添加 " << milkType << std::endl;
}
std::string getDescription() const override {
return beverage->getDescription() + " + " + milkType;
}
double cost() const override {
double milkCost = 3.0;
if (milkType == "燕麦奶" || milkType == "杏仁奶") milkCost = 5.0;
else if (milkType == "椰奶") milkCost = 4.0;
return beverage->cost() + milkCost;
}
int getCalories() const override {
int milkCalories = 60;
if (milkType == "脱脂牛奶") milkCalories = 35;
else if (milkType == "燕麦奶") milkCalories = 80;
else if (milkType == "杏仁奶") milkCalories = 40;
return beverage->getCalories() + milkCalories;
}
};
// 具体装饰器:糖浆
class SyrupDecorator : public BeverageDecorator {
private:
std::string syrupFlavor;
int pumps;
public:
explicit SyrupDecorator(std::unique_ptr<Beverage> bev, const std::string& flavor = "香草", int pumpCount = 1)
: BeverageDecorator(std::move(bev)), syrupFlavor(flavor), pumps(pumpCount) {
std::cout << "🍯 添加 " << pumps << " 泵 " << syrupFlavor << "糖浆" << std::endl;
}
std::string getDescription() const override {
return beverage->getDescription() + " + " + std::to_string(pumps) + "泵" + syrupFlavor + "糖浆";
}
double cost() const override {
double syrupCost = 2.0 * pumps;
if (syrupFlavor == "榛果" || syrupFlavor == "焦糖") syrupCost = 2.5 * pumps;
return beverage->cost() + syrupCost;
}
int getCalories() const override {
return beverage->getCalories() + (20 * pumps); // 每泵约20卡路里
}
};
// 具体装饰器:奶泡
class WhippedCreamDecorator : public BeverageDecorator {
private:
std::string creamType;
public:
explicit WhippedCreamDecorator(std::unique_ptr<Beverage> bev, const std::string& type = "经典奶泡")
: BeverageDecorator(std::move(bev)), creamType(type) {
std::cout << "☁️ 添加 " << creamType << std::endl;
}
std::string getDescription() const override {
return beverage->getDescription() + " + " + creamType;
}
double cost() const override {
double creamCost = 4.0;
if (creamType == "香草奶泡" || creamType == "肉桂奶泡") creamCost = 5.0;
return beverage->cost() + creamCost;
}
int getCalories() const override {
return beverage->getCalories() + 50; // 奶泡约50卡路里
}
};
// 具体装饰器:巧克力
class ChocolateDecorator : public BeverageDecorator {
private:
std::string chocolateType;
public:
explicit ChocolateDecorator(std::unique_ptr<Beverage> bev, const std::string& type = "黑巧克力")
: BeverageDecorator(std::move(bev)), chocolateType(type) {
std::cout << "🍫 添加 " << chocolateType << std::endl;
}
std::string getDescription() const override {
return beverage->getDescription() + " + " + chocolateType;
}</

1482

被折叠的 条评论
为什么被折叠?



