装饰模式是一种结构型设计模式,它允许你动态地给一个对象添加额外的职责,相比继承更加灵活。
1. 模式定义
装饰模式:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比生成子类更为灵活。
2. 模式结构
主要角色:
Component(抽象构件):定义对象的接口,可以给这些对象动态添加职责
ConcreteComponent(具体构件):定义具体的对象,可以给它添加职责
Decorator(抽象装饰类):继承/实现Component,并包含一个Component的引用
ConcreteDecorator(具体装饰类):向构件添加具体职责
代码:
#include <iostream>
#include <string>// 抽象构件
class Beverage {
public:virtual ~Beverage() = default;virtual std::string getDescription() const = 0;virtual double cost() const = 0;
};// 具体构件
class Espresso : public Beverage {
public:std::string getDescription() const override {return "Espresso";}double cost() const override {return 1.99;}
};// 抽象装饰类
class CondimentDecorator : public Beverage {
protected:Beverage* beverage;
public:explicit CondimentDecorator(Beverage* beverage) : beverage(beverage) {}virtual ~CondimentDecorator() { delete beverage; }std::string getDescription() const override = 0;
};// 具体装饰类A
class Milk : public CondimentDecorator {
public:explicit Milk(Beverage* beverage) : CondimentDecorator(beverage) {}std::string getDescription() const override {return beverage->getDescription() + ", Milk";}double cost() const override {return beverage->cost() + 0.20;}
};// 具体装饰类B
class Mocha : public CondimentDecorator {
public:explicit Mocha(Beverage* beverage) : CondimentDecorator(beverage) {}std::string getDescription() const override {return beverage->getDescription() + ", Mocha";}double cost() const override {return beverage->cost() + 0.30;}
};// 使用示例
int main() {// 创建基础饮料Beverage* beverage = new Espresso();std::cout << beverage->getDescription() << " $" << beverage->cost() << std::endl;// 用装饰类包装Beverage* beverage2 = new Milk(beverage);beverage2 = new Mocha(beverage2); // 再次装饰std::cout << beverage2->getDescription() << " $" << beverage2->cost() << std::endl;delete beverage2; // 会递归删除所有装饰对象return 0;
}
uml结构
3. 模式特点
优点:
比继承更灵活:动态添加或撤销功能
避免子类膨胀:通过组合而非继承扩展功能
符合开闭原则:对扩展开放,对修改关闭
缺点:
会产生许多小对象:增加系统复杂度
多层装饰时调试困难:需要逐层检查
4. 应用场景
扩展单个对象的功能,而不影响其他对象
动态透明地添加职责,可以随时撤销
不适合用子类扩展的情况(如子类数量爆炸)
5. 装饰模式 vs 继承
特性 | 装饰模式 | 继承 |
---|---|---|
扩展方式 | 动态组合 | 静态编译时确定 |
灵活性 | 高,可运行时调整 | 低,编译时固定 |
对象关系 | 组合关系 | 父子关系 |
类数量 | 装饰类数量较少 | 可能导致子类爆炸 |
装饰模式是扩展对象功能的一种灵活方式,特别适合在运行时动态添加或修改对象行为的场景。