设计模式每日硬核训练 Day 12:装饰器模式(Decorator Pattern)完整讲解与实战应用
🔄 回顾 Day 11:适配器模式小结
在 Day 11 中,我们学习了适配器模式(Adapter Pattern):
- 用于将“不兼容”的接口适配为目标接口,解决新旧系统之间的桥接问题。
- 强调“接口兼容、外部桥接”,通常用于第三方组件、老旧库的接入。
而今天我们要讲解的装饰器模式,则是:
在不改变原始类结构的前提下,动态为对象添加功能,是继承的优雅替代。
一、装饰器模式的核心动机
✅ 什么是装饰器?
装饰器模式(Decorator Pattern)用于:
- 将对象进行包装,在其行为之前/之后添加额外逻辑。
- 避免子类膨胀(继承爆炸),提升灵活性与组合性。
🎯 场景动机:
- IO 流中,数据流可多层压缩/加密/缓冲
- GUI 元素,增加边框、滚动条、阴影等效果
- 日志功能,输出前加时间戳、加颜色、记录文件
二、UML 结构图
+----------------+
| Component |<------------------+
+----------------+ |
| +operation() | |
+----------------+ |/\ ||| |
+----------------+ +-----------------+
| ConcreteComponent | | Decorator |
+----------------+ +-----------------+| - component: Component* || +operation() override |+-----------------+/\||+---------------------------+| ConcreteDecoratorA/B/... |+---------------------------+
三、角色解析
角色 | 职责说明 |
---|---|
Component | 抽象组件接口,定义操作行为 |
ConcreteComponent | 实际的核心功能类 |
Decorator | 抽象装饰器,持有组件引用,重写 operation |
ConcreteDecorator | 具体装饰功能的子类,添加增强行为 |
四、C++ 实现:消息输出增强系统
✅ Component 抽象接口
class IMessage {
public:virtual void send(const std::string& content) = 0;virtual ~IMessage() = default;
};
✅ 具体实现类
class SimpleMessage : public IMessage {
public:void send(const std::string& content) override {std::cout << content << std::endl;}
};
✅ 抽象装饰器
class MessageDecorator : public IMessage {
protected:std::unique_ptr<IMessage> wrappee_;
public:MessageDecorator(std::unique_ptr<IMessage> wrappee): wrappee_(std::move(wrappee)) {}
};
✅ 时间戳装饰器
class TimestampDecorator : public MessageDecorator {
public:using MessageDecorator::MessageDecorator;void send(const std::string& content) override {std::cout << "[Time] 2025-04-12: ";wrappee_->send(content);}
};
✅ 加密装饰器(简单)
class EncryptDecorator : public MessageDecorator {
public:using MessageDecorator::MessageDecorator;void send(const std::string& content) override {std::string encrypted = "<encrypted:" + content + ">";wrappee_->send(encrypted);}
};
✅ 使用示例
int main() {std::unique_ptr<IMessage> message = std::make_unique<SimpleMessage>();message = std::make_unique<TimestampDecorator>(std::move(message));message = std::make_unique<EncryptDecorator>(std::move(message));message->send("Hello World!");return 0;
}
输出:
[Time] 2025-04-12: <encrypted:Hello World!>
五、装饰器 vs 继承
比较项 | 装饰器 | 子类继承 |
---|---|---|
可组合性 | ✅ 支持任意层级嵌套 | ❌ 单继承不支持组合 |
可扩展性 | ✅ 添加装饰器即可 | ❌ 添加功能需新建子类 |
运行时决定 | ✅ 装饰器可动态组合 | ❌ 继承结构在编译期固定 |
六、实战应用举例
场景 | 装饰器用途说明 |
---|---|
C++ IO Stream | std::istream → std::ifstream → std::istringstream |
日志系统 | 添加标签、时间、线程 ID |
游戏角色行为 | 攻击装饰:暴击 → 穿透 → 吸血 |
网络请求处理链 | 添加重试机制 → 添加限流 → 添加缓存 |
Web Filter 框架 | Spring Filter Chain(Java 中广泛使用) |
七、与其他结构型模式对比
模式 | 意图 | 是否更改原对象 |
---|---|---|
Decorator | 增强已有对象功能 | ❌(包裹) |
Proxy | 控制访问、权限、懒加载 | ❌(控制访问) |
Adapter | 接口转换,兼容老接口 | ❌(桥接) |
Bridge | 接口与实现分离,双维度变化 | ✅(实现层变化) |
八、面试回答模板
“我们使用装饰器模式为日志系统添加了格式增强功能,比如加上时间戳、线程信息以及日志等级,而不需要改动原有的日志类。装饰器让我们可以灵活组合这些功能,并且在运行时动态配置,适合多种环境。”
✅ 建议强调运行时组合、非侵入式增强、支持多层扩展等特性。
九、记忆口诀
“增强不改类,功能可叠加;运行时组合,结构更优雅。”
十、明日预告:Day 13
桥接模式(Bridge Pattern):将接口与实现解耦,适用于双维度扩展场景。