2025/9/29日 每日总结 设计模式实践:装饰模式之手机功能动态升级案例解析

设计模式实践:装饰模式之手机功能动态升级案例解析

在软件开发中,经常需要给现有对象动态添加新功能,同时又不改变其原有结构。装饰模式作为一种灵活的结构型设计模式,能够在不修改原类代码的前提下,通过“包装”的方式扩展对象功能。本文将通过“手机功能升级”的趣味案例,详细拆解装饰模式的实现逻辑与应用价值。

一、实验背景与需求

本次实践的核心需求是模拟手机功能的逐步升级,实现不同层级的来电提醒功能:

  1. 基础款(SimplePhone):来电时仅发出声音提示

  2. 进阶款(JarPhone):在声音提示基础上,增加振动功能

  3. 高端款(ComplexPhone):在声音、振动基础上,再增加灯光闪烁提示

  4. 约束:不修改原有手机类的代码,支持功能的动态组合与扩展

二、装饰模式核心结构

装饰模式的关键在于通过抽象装饰器类包装具体组件,具体装饰器类实现新增功能,且所有组件和装饰器都遵循同一抽象接口。本次案例的结构设计如下:

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. 支持功能的灵活组合(如直接给简单手机添加灯光功能)

  3. 客户端可以统一处理原始对象和装饰后的对象,无需区分类型

五、装饰模式核心优势与特性

1. 核心优势

  • 遵循开闭原则:扩展功能时无需修改原有代码,仅需新增装饰器类

  • 功能动态组合:可根据需求灵活组合不同功能,无需创建大量子类

  • 低耦合:装饰器与被装饰对象通过抽象接口交互,耦合度低

  • 透明性:客户端使用装饰后的对象与原始对象的方式完全一致

    2. 与继承的对比

    特性 装饰模式 继承
    功能扩展 动态扩展,运行时组合 静态扩展,编译时确定
    代码冗余 低(装饰器复用性高) 高(需创建大量子类)
    灵活性 高(支持任意组合) 低(功能固定)
    耦合度 低(依赖抽象接口) 高(依赖具体子类)

    六、适用场景总结

    装饰模式特别适合以下场景:

  • 需动态给对象添加/移除功能,且不改变其原有结构

  • 避免通过继承产生大量子类(如手机功能有N种组合时,装饰模式仅需N个装饰器,而继承需2^N个子类)

  • 需灵活组合多个功能(如同时添加振动、灯光、铃声自定义等功能)

  • 希望客户端以统一方式处理原始对象和扩展后的对象
    通过本次“手机功能升级”的实践案例,深刻体会到装饰模式在功能扩展场景中的灵活性。它既解决了继承带来的子类爆炸问题,又保持了代码的低耦合和可维护性。在实际开发中,当遇到日志记录、缓存、权限控制等需要动态扩展的场景时,装饰模式都是一个非常理想的解决方案。

posted @ 2025-12-29 14:32  Moonbeamsc  阅读(11)  评论(0)    收藏  举报
返回顶端