C++设计模式之装饰器模式讲解
·
装饰器模式(Decorator Pattern)是一种结构型设计模式,它允许在不改变原有对象结构的情况下,动态地给对象添加额外的职责(功能)。这种模式通过创建一个包装对象(装饰器)来包裹真实对象,从而在保持接口一致的前提下扩展功能。
装饰器模式的核心角色
- 抽象组件(Component):定义对象的接口,可以给这些对象动态添加职责
- 具体组件(Concrete Component):实现抽象组件接口,是被装饰的原始对象
- 抽象装饰器(Decorator):继承或实现抽象组件,包含一个指向抽象组件的引用
- 具体装饰器(Concrete Decorator):实现抽象装饰器,给组件添加具体的额外功能
装饰器模式的实现示例
下面以"咖啡订单"为例展示装饰器模式的实现,我们可以给基础咖啡动态添加各种配料(如牛奶、糖、巧克力等):
#include <iostream>
#include <string>
// 抽象组件:咖啡
class Coffee {
public:
virtual std::string getDescription() const = 0;
virtual double cost() const = 0;
virtual ~Coffee() = default;
};
// 具体组件:基础咖啡
class Espresso : public Coffee {
public:
std::string getDescription() const override {
return "浓缩咖啡";
}
double cost() const override {
return 25.0;
}
};
class Americano : public Coffee {
public:
std::string getDescription() const override {
return "美式咖啡";
}
double cost() const override {
return 20.0;
}
};
// 抽象装饰器:配料装饰器
class CondimentDecorator : public Coffee {
protected:
Coffee* coffee; // 被装饰的咖啡
public:
CondimentDecorator(Coffee* coffee) : coffee(coffee) {}
~CondimentDecorator() override {
delete coffee; // 释放被装饰的对象
}
};
// 具体装饰器:牛奶
class Milk : public CondimentDecorator {
public:
Milk(Coffee* coffee) : CondimentDecorator(coffee) {}
std::string getDescription() const override {
return coffee->getDescription() + ", 牛奶";
}
double cost() const override {
return coffee->cost() + 5.0; // 牛奶加价5元
}
};
// 具体装饰器:糖
class Sugar : public CondimentDecorator {
public:
Sugar(Coffee* coffee) : CondimentDecorator(coffee) {}
std::string getDescription() const override {
return coffee->getDescription() + ", 糖";
}
double cost() const override {
return coffee->cost() + 2.0; // 糖加价2元
}
};
// 具体装饰器:巧克力
class Chocolate : public CondimentDecorator {
public:
Chocolate(Coffee* coffee) : CondimentDecorator(coffee) {}
std::string getDescription() const override {
return coffee->getDescription() + ", 巧克力";
}
double cost() const override {
return coffee->cost() + 8.0; // 巧克力加价8元
}
};
// 客户端使用
int main() {
// 点一杯纯浓缩咖啡
Coffee* espresso = new Espresso();
std::cout << espresso->getDescription() << " 价格: " << espresso->cost() << "元" << std::endl;
delete espresso;
// 点一杯加牛奶和糖的美式咖啡
Coffee* coffee = new Sugar(new Milk(new Americano()));
std::cout << coffee->getDescription() << " 价格: " << coffee->cost() << "元" << std::endl;
delete coffee;
// 点一杯加双份巧克力的浓缩咖啡
Coffee* fancyCoffee = new Chocolate(new Chocolate(new Espresso()));
std::cout << fancyCoffee->getDescription() << " 价格: " << fancyCoffee->cost() << "元" << std::endl;
delete fancyCoffee;
return 0;
}
装饰器模式的工作原理
- 装饰器与被装饰对象实现相同的接口(或继承相同的抽象类)
- 装饰器包含一个指向被装饰对象的引用
- 装饰器在调用被装饰对象的方法前后,可以添加额外的行为
- 可以通过嵌套多个装饰器,实现多种功能的组合
装饰器模式与继承的对比
- 继承:在编译时静态添加功能,不够灵活,可能导致类爆炸
- 装饰器:在运行时动态添加功能,更灵活,可以组合多个功能
装饰器模式的应用场景
- 需要动态地给对象添加或移除功能
- 需要给对象添加多个可组合的功能
- 不适合使用继承来扩展功能(如final类或类层次复杂)
- 希望在不影响其他对象的情况下,为单个对象添加功能
装饰器模式的优缺点
优点:
- 可以动态地给对象添加功能,灵活性高
- 可以组合多个装饰器,实现功能的叠加
- 遵循开放-封闭原则,扩展新功能无需修改原有代码
- 避免了使用继承带来的类爆炸问题
缺点:
- 增加了系统复杂度,需要理解多个装饰器的工作方式
- 装饰器嵌套过多可能导致代码可读性下降
- 对于多次装饰的对象,调试和排错可能比较困难
装饰器模式在C++标准库中也有应用,例如IO流库中的std::ifstream、std::ofstream配合std::ios::binary、std::ios::app等标志,以及std::endl等操纵符,都是装饰器模式思想的体现。
更多推荐


所有评论(0)