2025/9/29日 每日总结 设计模式实践:装饰模式之手机功能动态升级案例解析
设计模式实践:装饰模式之手机功能动态升级案例解析
在软件开发中,经常需要给现有对象动态添加新功能,同时又不改变其原有结构。装饰模式作为一种灵活的结构型设计模式,能够在不修改原类代码的前提下,通过“包装”的方式扩展对象功能。本文将通过“手机功能升级”的趣味案例,详细拆解装饰模式的实现逻辑与应用价值。
一、实验背景与需求
本次实践的核心需求是模拟手机功能的逐步升级,实现不同层级的来电提醒功能:
-
基础款(SimplePhone):来电时仅发出声音提示
-
进阶款(JarPhone):在声音提示基础上,增加振动功能
-
高端款(ComplexPhone):在声音、振动基础上,再增加灯光闪烁提示
-
约束:不修改原有手机类的代码,支持功能的动态组合与扩展
二、装饰模式核心结构
装饰模式的关键在于通过抽象装饰器类包装具体组件,具体装饰器类实现新增功能,且所有组件和装饰器都遵循同一抽象接口。本次案例的结构设计如下:
1. 核心组件划分
| 组件类型 | 具体实现 | 职责描述 |
|---|---|---|
| 抽象组件 | Phone | 定义手机的核心接口(来电提醒、功能描述),统一组件和装饰器的行为规范 |
| 具体组件 | SimplePhone | 基础手机类,实现核心功能(声音提示),是被装饰的原始对象 |
| 抽象装饰器 | PhoneDecoration | 继承Phone接口,持有被装饰的Phone对象,实现接口的默认转发逻辑 |
| 具体装饰器 | JarPhone、ComplexPhone | 分别实现振动、灯光闪烁功能,在转发原始功能的基础上添加新特性 |
2. 类图结构
┌─────────────────┐
│ Phone │ ← 抽象组件(统一接口)
├─────────────────┤
│ + receiveCall(): void │ ← 来电提醒核心方法
│ + getDescription(): string │ ← 功能描述方法
└─────────────────┘
▲
│
┌───────────────┬───────────────┐
│ SimplePhone │ PhoneDecoration │
├───────────────┤───────────────┤
│ + receiveCall() │ - phone: Phone │ ← 持有被装饰对象
│ + getDescription() │ + PhoneDecoration(phone: Phone) │
└───────────────┘───────────────┘
▲
│
┌───────────────┬───────────────┐
│ JarPhone │ ComplexPhone │
├───────────────┤───────────────┤
│ + JarPhone(phone: Phone) │ + ComplexPhone(phone: Phone) │
│ + receiveCall() │ + receiveCall() │ ← 扩展新功能
│ + getDescription() │ + getDescription() │ ← 更新描述
└───────────────┘───────────────┘
三、完整实现代码(C++)
1. 抽象组件:Phone.h
#ifndef PHONE_H
#define PHONE_H
#include <iostream>
#include <string>
// 抽象手机类,定义核心接口
class Phone {
public:
virtual ~Phone() = default; // 虚析构函数,确保子类正确析构
virtual void receiveCall() = 0; // 来电提醒功能(纯虚函数)
virtual std::string getDescription() = 0; // 获取功能描述(纯虚函数)
};
#endif
2. 具体组件:SimplePhone.h
#ifndef SIMPLE_PHONE_H
#define SIMPLE_PHONE_H
#include "Phone.h"
// 基础手机类,实现核心功能
class SimplePhone : public Phone {
public:
// 来电时发出声音提示
void receiveCall() override {
std::cout << "发出声音提示" << std::endl;
}
// 返回功能描述
std::string getDescription() override {
return "简单手机(声音提示)";
}
};
endif
### 3. 抽象装饰器:PhoneDecoration.h
```cpp
#ifndef PHONE_DECORATION_H
#define PHONE_DECORATION_H
#include "Phone.h"
// 抽象装饰器类,包装Phone对象
class PhoneDecoration : public Phone {
protected:
Phone* phone; // 持有被装饰的手机实例
public:
// 构造函数:传入被装饰的手机对象
explicit PhoneDecoration(Phone* ph) : phone(ph) {}
// 析构函数:释放被装饰对象的内存
virtual ~PhoneDecoration() {
delete phone;
}
// 转发来电提醒功能(默认调用被装饰对象的方法)
void receiveCall() override {
if (phone) {
phone->receiveCall();
}
}
// 转发功能描述(默认返回被装饰对象的描述)
std::string getDescription() override {
return phone ? phone->getDescription() : "未知手机";
}
};
#endif
4. 具体装饰器:JarPhone.h(添加振动功能)
#ifndef JAR_PHONE_H
#define JAR_PHONE_H
#include "PhoneDecoration.h"
// 具体装饰器:为手机添加振动功能
class JarPhone : public PhoneDecoration {
public:
explicit JarPhone(Phone* ph) : PhoneDecoration(ph) {}
// 重写来电提醒:先执行原有功能,再添加振动
void receiveCall() override {
PhoneDecoration::receiveCall(); // 调用被装饰对象的声音提示
addVibration(); // 新增振动功能
}
// 重写功能描述:添加振动功能说明
std::string getDescription() override {
return PhoneDecoration::getDescription() + " + 振动功能";
}
private:
// 新增的振动功能
void addVibration() {
std::cout << "手机开始振动" << std::endl;
}
};
5. 具体装饰器:ComplexPhone.h(添加灯光闪烁功能)
#ifndef COMPLEX_PHONE_H
#define COMPLEX_PHONE_H
#include "PhoneDecoration.h"
// 具体装饰器:为手机添加灯光闪烁功能
class ComplexPhone : public PhoneDecoration {
public:
explicit ComplexPhone(Phone* ph) : PhoneDecoration(ph) {}
// 重写来电提醒:先执行原有功能,再添加灯光闪烁
void receiveCall() override {
PhoneDecoration::receiveCall(); // 调用被装饰对象的已有功能(声音+振动)
addLightFlash(); // 新增灯光闪烁功能
}
// 重写功能描述:添加灯光闪烁功能说明
std::string getDescription() override {
return PhoneDecoration::getDescription() + " + 灯光闪烁";
}
private:
// 新增的灯光闪烁功能
void addLightFlash() {
std::cout << "灯光闪烁提示" << std::endl;
}
};
6. 客户端测试代码:main.cpp
#include <iostream>
#include "SimplePhone.h"
#include "JarPhone.h"
#include "ComplexPhone.h"
// 测试函数:统一测试不同类型手机的功能
void testPhoneFunction(Phone* phone) {
std::cout << "=== " << phone->getDescription() << " ===" << std::endl;
std::cout << "来电提醒功能:" << std::endl;
phone->receiveCall();
std::cout << std::endl;
}
int main() {
// 1. 测试基础款:简单手机(仅声音)
Phone* simplePhone = new SimplePhone();
testPhoneFunction(simplePhone);
// 2. 测试进阶款:Jar手机(声音+振动)
Phone* jarPhone = new JarPhone(new SimplePhone());
testPhoneFunction(jarPhone);
// 3. 测试高端款:复杂手机(声音+振动+灯光)
Phone* complexPhone = new ComplexPhone(new JarPhone(new SimplePhone()));
testPhoneFunction(complexPhone);
// 4. 灵活组合:简单手机直接添加灯光功能(声音+灯光)
Phone* complexPhone2 = new ComplexPhone(new SimplePhone());
testPhoneFunction(complexPhone2);
// 清理内存
delete simplePhone;
delete jarPhone;
delete complexPhone;
delete complexPhone2;
return 0;
}
四、运行结果
=== 简单手机(声音提示) ===
来电提醒功能:
发出声音提示
=== 简单手机(声音提示) + 振动功能 ===
来电提醒功能:
发出声音提示
手机开始振动
=== 简单手机(声音提示) + 振动功能 + 灯光闪烁 ===
来电提醒功能:
发出声音提示
手机开始振动
灯光闪烁提示
=== 简单手机(声音提示) + 灯光闪烁 ===
来电提醒功能:
发出声音提示
灯光闪烁提示
从运行结果可以看出:
-
装饰模式实现了功能的动态扩展,无需修改原有类代码
-
支持功能的灵活组合(如直接给简单手机添加灯光功能)
-
客户端可以统一处理原始对象和装饰后的对象,无需区分类型
五、装饰模式核心优势与特性
1. 核心优势
-
遵循开闭原则:扩展功能时无需修改原有代码,仅需新增装饰器类
-
功能动态组合:可根据需求灵活组合不同功能,无需创建大量子类
-
低耦合:装饰器与被装饰对象通过抽象接口交互,耦合度低
-
透明性:客户端使用装饰后的对象与原始对象的方式完全一致
2. 与继承的对比
特性 装饰模式 继承 功能扩展 动态扩展,运行时组合 静态扩展,编译时确定 代码冗余 低(装饰器复用性高) 高(需创建大量子类) 灵活性 高(支持任意组合) 低(功能固定) 耦合度 低(依赖抽象接口) 高(依赖具体子类) 六、适用场景总结
装饰模式特别适合以下场景:
-
需动态给对象添加/移除功能,且不改变其原有结构
-
避免通过继承产生大量子类(如手机功能有N种组合时,装饰模式仅需N个装饰器,而继承需2^N个子类)
-
需灵活组合多个功能(如同时添加振动、灯光、铃声自定义等功能)
-
希望客户端以统一方式处理原始对象和扩展后的对象
通过本次“手机功能升级”的实践案例,深刻体会到装饰模式在功能扩展场景中的灵活性。它既解决了继承带来的子类爆炸问题,又保持了代码的低耦合和可维护性。在实际开发中,当遇到日志记录、缓存、权限控制等需要动态扩展的场景时,装饰模式都是一个非常理想的解决方案。

浙公网安备 33010602011771号