装饰器模式(Decorator Pattern)是一种结构型设计模式,它允许向一个现有的对象添加新的功能,同时又不改变其结构。这种模式创建了一个装饰器类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
beverage = std::make_shared(beverage); / beverage = std::make_unique(std::move(beverage))
创建装饰器链,调用时会逐层委托到基础组件装饰器模式通过组合而非继承来扩展功能,为设计提供了更大的灵活性,是替代大量子类继承的有效解决方案。
#include
#include
#include
// 抽象组件接口
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:
std::unique_ptr<Beverage> beverage;
public:
CondimentDecorator(std::unique_ptr<Beverage> b) : beverage(std::move(b)) {}
};
// 具体装饰器
class Mocha : public CondimentDecorator {
public:
using CondimentDecorator::CondimentDecorator;
std::string getDescription() const override {
return beverage->getDescription() + ", Mocha";
}
double cost() const override {
return beverage->cost() + 0.20;
}
};
class Whip : public CondimentDecorator {
public:
using CondimentDecorator::CondimentDecorator;
std::string getDescription() const override {
return beverage->getDescription() + ", Whip";
}
double cost() const override {
return beverage->cost() + 0.10;
}
};
int main() {
// 创建基础饮料
auto beverage = std::make_unique<Espresso>();
std::cout << beverage->getDescription()
<< " $" << beverage->cost() << std::endl;
// 添加装饰
beverage = std::make_unique<Mocha>(std::move(beverage));
beverage = std::make_unique<Whip>(std::move(beverage));
std::cout << beverage->getDescription()
<< " $" << beverage->cost() << std::endl;
return 0;
}
InputStream
/OutputStream
、Python的file
对象包装。#include
#include
#include
#include
#include
// 抽象组件接口
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 HouseBlend : public Beverage {
public:
std::string getDescription() const override {
return "House Blend Coffee";
}
double cost() const override {
return 0.89;
}
};
// 抽象装饰器
class CondimentDecorator : public Beverage {
protected:
std::shared_ptr<Beverage> beverage;
public:
CondimentDecorator(std::shared_ptr<Beverage> b) : beverage(std::move(b)) {}
};
// 具体装饰器
class Mocha : public CondimentDecorator {
private:
int shots;
public:
Mocha(std::shared_ptr<Beverage> b, int s = 1)
: CondimentDecorator(std::move(b)), shots(s) {}
std::string getDescription() const override {
return beverage->getDescription() + ", Mocha(" + std::to_string(shots) + ")";
}
double cost() const override {
return beverage->cost() + 0.20 * shots;
}
};
class Whip : public CondimentDecorator {
public:
using CondimentDecorator::CondimentDecorator;
std::string getDescription() const override {
return beverage->getDescription() + ", Whip";
}
double cost() const override {
return beverage->cost() + 0.10;
}
};
// 装饰器工厂
enum class Condiment {
MOCHA, WHIP
};
class BeverageFactory {
public:
static std::shared_ptr<Beverage> addCondiment(
std::shared_ptr<Beverage> bev,
Condiment condiment,
int param = 1
) {
switch(condiment) {
case Condiment::MOCHA:
return std::make_shared<Mocha>(bev, param);
case Condiment::WHIP:
return std::make_shared<Whip>(bev);
default:
return bev;
}
}
};
// 构建器模式
class BeverageBuilder {
private:
std::shared_ptr<Beverage> beverage;
public:
explicit BeverageBuilder(std::shared_ptr<Beverage> base) : beverage(std::move(base)) {}
BeverageBuilder& addMocha(int shots = 1) {
beverage = std::make_shared<Mocha>(beverage, shots);
return *this;
}
BeverageBuilder& addWhip() {
beverage = std::make_shared<Whip>(beverage);
return *this;
}
std::shared_ptr<Beverage> build() {
return beverage;
}
};
int main() {
// 使用工厂模式
auto beverage1 = std::make_shared<Espresso>();
beverage1 = BeverageFactory::addCondiment(beverage1, Condiment::MOCHA, 2);
beverage1 = BeverageFactory::addCondiment(beverage1, Condiment::WHIP);
std::cout << beverage1->getDescription()
<< " $" << beverage1->cost() << std::endl;
// 使用构建器模式
auto beverage2 = BeverageBuilder(std::make_shared<HouseBlend>())
.addMocha()
.addWhip()
.addMocha()
.build();
std::cout << beverage2->getDescription()
<< " $" << beverage2->cost() << std::endl;
return 0;
}
// 1. 创建装饰器工厂
enum class Condiment {
MOCHA, WHIP
};
class BeverageFactory {
public:
static std::unique_ptr<Beverage> addCondiment(
std::unique_ptr<Beverage> bev,
Condiment condiment
) {
switch(condiment) {
case Condiment::MOCHA:
return std::make_unique<Mocha>(std::move(bev));
case Condiment::WHIP:
return std::make_unique<Whip>(std::move(bev));
default:
return bev;
}
}
};
using BeveragePtr = std::shared_ptr<Beverage>;
// 避免所有权转移问题,允许多处引用同一对象
// 构建器模式示例
class BeverageBuilder {
private:
BeveragePtr beverage;
public:
explicit BeverageBuilder(BeveragePtr base) : beverage(std::move(base)) {}
BeverageBuilder& addMocha() {
beverage = std::make_shared<Mocha>(beverage);
return *this;
}
BeverageBuilder& addWhip() {
beverage = std::make_shared<Whip>(beverage);
return *this;
}
BeveragePtr build() {
return beverage;
}
};
// 使用方式
auto beverage = BeverageBuilder(std::make_shared<Espresso>())
.addMocha()
.addWhip()
.build();
// 在装饰器构造函数中添加验证逻辑
Mocha(std::unique_ptr<Beverage> b) : CondimentDecorator(std::move(b)) {
// 可以添加对b类型的检查,防止非法组合
}
class Mocha : public CondimentDecorator {
private:
int shots; // 支持多份摩卡
public:
Mocha(std::unique_ptr<Beverage> b, int s = 1)
: CondimentDecorator(std::move(b)), shots(s) {}
double cost() const override {
return beverage->cost() + 0.20 * shots;
}
};
class RemovableCondiment : public CondimentDecorator {
public:
using CondimentDecorator::CondimentDecorator;
virtual std::unique_ptr<Beverage> remove() = 0;
};
unique_ptr
表示独占所有权,同一对象只能有一个指针指向它std::move
转移所有权,原指针将变为空unique_ptr
,只能移动shared_ptr
使用引用计数,允许多个指针共享同一对象shared_ptr
被销毁时,对象才被释放shared_ptr
,引用计数增加特性 | std::unique_ptr |
std::shared_ptr |
---|---|---|
所有权 | 独占 | 共享 |
转移方式 | 必须使用std::move |
直接复制 |
原指针状态 | 转移后变为空 | 仍然有效,引用计数增加 |
内存释放时机 | 指针被销毁时 | 最后一个指针被销毁时 |
线程安全性 | 无特殊同步 | 引用计数操作是线程安全的 |
性能 | 轻量级,无引用计数开销 | 有引用计数开销 |
适用场景 | 对象所有权清晰,避免共享 | 需要多个所有者或生命周期管理复杂的场景 |
// 使用unique_ptr(原示例)
auto beverage = std::make_unique<Espresso>();
beverage = std::make_unique<Mocha>(std::move(beverage)); // 原指针失效
// 使用shared_ptr
auto beverage = std::make_shared<Espresso>();
auto whippedBeverage = std::make_shared<Whip>(beverage); // 原指针仍有效
通过内存布局和函数调用栈来理解。执行以下代码:
auto beverage = std::make_shared<Espresso>(); // 步骤1
beverage = std::make_shared<Whip>(beverage); // 步骤2
beverage = std::make_shared<Mocha>(beverage); // 步骤3
栈内存 堆内存
+--------+ +-------------+
| beverage|---------->| Espresso对象 |
+--------+ +-------------+
栈内存 堆内存
+--------+ +-------------+
| beverage|---------->| Whip对象 |
+--------+ +-------------+
| beverage_ |
+---------->| Espresso对象 |
+-------------+
栈内存 堆内存
+--------+ +-------------+
| beverage|---------->| Mocha对象 |
+--------+ +-------------+
| beverage_ |
+---------->| Whip对象 |
+-------------+
| beverage_ |
+---------->| Espresso对象 |
+-------------+
当我们调用beverage->cost()
时,实际发生的是:
静态类型与动态类型:
beverage
的静态类型是Beverage*
(基类指针)Mocha
(运行时实际指向的对象类型)虚函数表(VTable):
Mocha
的虚函数表中,cost()
条目指向Mocha::cost()
实现调用栈展开:
// 调用 beverage->cost()
Mocha::cost() { // 动态类型是Mocha,通过VTable找到此函数
return beverage_->cost() + 0.20; // beverage_指向Whip对象
// ↑ 此处发生多态调用
}
// 执行 Whip::cost()
Whip::cost() { // 通过Whip对象的VTable找到此函数
return beverage_->cost() + 0.10; // beverage_指向Espresso对象
// ↑ 再次发生多态调用
}
// 执行 Espresso::cost()
Espresso::cost() { // 通过Espresso对象的VTable找到此函数
return 1.99;
}
// 错误示例:直接递归调用自身
Mocha::cost() {
return cost() + 0.20; // 无限递归,栈溢出
}
// 正确实现:通过基类接口调用
Mocha::cost() {
return beverage_->cost() + 0.20; // 调用的是另一个对象的cost()
}
auto base = std::make_shared<Espresso>();
std::cout << "Base addr: " << base.get() << "\n";
auto withWhip = std::make_shared<Whip>(base);
std::cout << "Whip addr: " << withWhip.get() << "\n";
std::cout << "Whip's inner addr: " << withWhip->getInnerAddr() << "\n";
// 在Whip类中添加辅助方法
class Whip : public CondimentDecorator {
public:
Beverage* getInnerAddr() const { return beverage_.get(); }
};
输出结果类似:
Base addr: 0x12345678
Whip addr: 0x87654321
Whip's inner addr: 0x12345678 // 与base地址相同