结构型模式:④装饰模式(Decorator Pattern)

结构型模式:④装饰模式(Decorator Pattern)

核心思想

动态地给对象添加额外职责,无需修改原对象的类结构,也无需创建大量子类(避免 “子类爆炸”)。核心是通过「组合关系」替代「继承关系」:
抽象组件(Component):定义被装饰对象的统一接口;
具体组件(ConcreteComponent):基础对象(被装饰的核心);
抽象装饰器(Decorator):持有抽象组件的引用,实现抽象组件接口(确保与被装饰对象接口一致);
具体装饰器(ConcreteDecorator):继承抽象装饰器,在转发调用基础上添加额外职责。

核心本质

包装(Wrap)+ 转发(Delegate)+ 扩展(Extend),客户端可通过嵌套装饰器动态组合多个额外职责。

C语言编写

场景示例

咖啡订单系统:
抽象组件(CoffeeComponent):定义咖啡的统一接口(获取描述、获取价格);
具体组件(Americano):基础咖啡(美式咖啡,无额外配料);
抽象装饰器(CoffeeDecorator):持有咖啡组件指针,实现统一接口;
具体装饰器(MilkDecorator、SugarDecorator):给咖啡加牛奶、加糖,添加额外价格和描述。

关键要点

1.接口统一:抽象组件(CoffeeComponent)定义 GetDesc/GetPrice 统一接口,基础咖啡和所有装饰器都实现该接口,确保客户端操作一致。
2.组合核心:抽象装饰器(CoffeeDecorator)通过成员指针 component 持有被装饰对象(基础咖啡或已装饰的咖啡),替代继承实现功能复用。
3.转发 + 扩展:具体装饰器(如 MilkDecorator)先转发调用被装饰对象的接口(获取基础描述 / 价格),再添加额外逻辑(加价、追加描述),实现 “不修改原对象” 的扩展。
4.嵌套装饰:客户端可通过多次嵌套装饰器(create_milk_decorator → create_sugar_decorator)动态组合多个额外职责,灵活性极高。
5.内存安全:抽象装饰器的 Destroy 方法需递归销毁被装饰对象,避免仅销毁装饰器导致的底层组件内存泄漏。
6.开闭原则:新增配料(如 “奶泡”)时,只需新增 FoamDecorator 具体装饰器,无需修改基础咖啡类和现有装饰器。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 最大描述长度(简化示例)
#define MAX_DESC 128

// -------------------------- 1. 抽象组件(Component):咖啡统一接口 --------------------------
typedef struct CoffeeComponent {
    // 统一接口:获取咖啡描述
    void (*GetDesc)(struct CoffeeComponent* self, char* desc);
    // 统一接口:获取咖啡价格
    float (*GetPrice)(struct CoffeeComponent* self);
    void (*Destroy)(struct CoffeeComponent* self);
} CoffeeComponent;

// -------------------------- 2. 具体组件(ConcreteComponent):基础咖啡(美式) --------------------------
typedef struct Americano {
    CoffeeComponent base; // 模拟继承:包含抽象组件接口
    float price;          // 基础价格
    char desc[MAX_DESC];  // 基础描述
} Americano;

// 美式咖啡:获取描述
void americano_get_desc(CoffeeComponent* self, char* desc) {
    Americano* coffee = (Americano*)self;
    strncpy(desc, coffee->desc, MAX_DESC);
}

// 美式咖啡:获取价格
float americano_get_price(CoffeeComponent* self) {
    Americano* coffee = (Americano*)self;
    return coffee->price;
}

// 美式咖啡:销毁
void americano_destroy(CoffeeComponent* self) {
    if (self != NULL) {
        free(self);
    }
}

// 创建基础美式咖啡
CoffeeComponent* create_americano() {
    Americano* coffee = (Americano*)malloc(sizeof(Americano));
    coffee->price = 15.0f;
    strncpy(coffee->desc, "美式咖啡", MAX_DESC);
    // 绑定抽象接口
    coffee->base.GetDesc = americano_get_desc;
    coffee->base.GetPrice = americano_get_price;
    coffee->base.Destroy = americano_destroy;
    return (CoffeeComponent*)coffee;
}

// -------------------------- 3. 抽象装饰器(Decorator):持有咖啡组件,实现统一接口 --------------------------
typedef struct CoffeeDecorator {
    CoffeeComponent base;          // 模拟继承:实现抽象组件接口
    CoffeeComponent* component;    // 组合核心:持有被装饰的咖啡组件(基础咖啡/已装饰咖啡)
} CoffeeDecorator;

// 抽象装饰器:转发获取描述(子类需重写扩展)
void decorator_get_desc(CoffeeComponent* self, char* desc) {
    CoffeeDecorator* decorator = (CoffeeDecorator*)self;
    // 转发调用被装饰组件的接口
    decorator->component->GetDesc(decorator->component, desc);
}

// 抽象装饰器:转发获取价格(子类需重写扩展)
float decorator_get_price(CoffeeComponent* self) {
    CoffeeDecorator* decorator = (CoffeeDecorator*)self;
    // 转发调用被装饰组件的接口
    return decorator->component->GetPrice(decorator->component);
}

// 抽象装饰器:销毁(需递归销毁被装饰组件)
void decorator_destroy(CoffeeComponent* self) {
    if (self != NULL) {
        CoffeeDecorator* decorator = (CoffeeDecorator*)self;
        decorator->component->Destroy(decorator->component); // 销毁被装饰组件
        free(self);
    }
}

// 创建抽象装饰器(供具体装饰器复用初始化逻辑)
CoffeeDecorator* create_coffee_decorator(CoffeeComponent* component) {
    CoffeeDecorator* decorator = (CoffeeDecorator*)malloc(sizeof(CoffeeDecorator));
    // 绑定基础转发接口(具体装饰器可重写)
    decorator->base.GetDesc = decorator_get_desc;
    decorator->base.GetPrice = decorator_get_price;
    decorator->base.Destroy = decorator_destroy;
    // 绑定被装饰组件(组合关系)
    decorator->component = component;
    return decorator;
}

// -------------------------- 4. 具体装饰器(ConcreteDecorator):加牛奶 --------------------------
typedef struct MilkDecorator {
    CoffeeDecorator base; // 模拟继承:包含抽象装饰器
    float add_price;      // 额外价格(牛奶加价)
    char add_desc[MAX_DESC]; // 额外描述(牛奶)
} MilkDecorator;

// 加牛奶:扩展描述(基础描述 + 牛奶)
void milk_get_desc(CoffeeComponent* self, char* desc) {
    MilkDecorator* decorator = (MilkDecorator*)self;
    // 先转发获取被装饰组件的描述(如“美式咖啡”)
    decorator->base.component->GetDesc(decorator->base.component, desc);
    // 扩展描述
    strncat(desc, " + 牛奶", MAX_DESC - strlen(desc) - 1);
}

// 加牛奶:扩展价格(基础价格 + 牛奶加价)
float milk_get_price(CoffeeComponent* self) {
    MilkDecorator* decorator = (MilkDecorator*)self;
    // 先转发获取被装饰组件的价格(如15元)
    return decorator->base.component->GetPrice(decorator->base.component) + decorator->add_price;
}

// 创建“加牛奶”装饰器
CoffeeComponent* create_milk_decorator(CoffeeComponent* component) {
    MilkDecorator* decorator = (MilkDecorator*)malloc(sizeof(MilkDecorator));
    // 初始化抽象装饰器(绑定被装饰组件)
    decorator->base = *create_coffee_decorator(component);
    // 重写抽象装饰器的接口(扩展功能)
    decorator->base.base.GetDesc = milk_get_desc;
    decorator->base.base.GetPrice = milk_get_price;
    // 额外配置(牛奶的加价和描述)
    decorator->add_price = 3.0f;
    strncpy(decorator->add_desc, "牛奶", MAX_DESC);
    return (CoffeeComponent*)decorator;
}

// -------------------------- 5. 具体装饰器(ConcreteDecorator):加糖 --------------------------
typedef struct SugarDecorator {
    CoffeeDecorator base; // 模拟继承:包含抽象装饰器
    float add_price;      // 额外价格(糖加价)
    char add_desc[MAX_DESC]; // 额外描述(糖)
} SugarDecorator;

// 加糖:扩展描述(基础描述 + 糖)
void sugar_get_desc(CoffeeComponent* self, char* desc) {
    SugarDecorator* decorator = (SugarDecorator*)self;
    // 转发获取被装饰组件的描述(如“美式咖啡 + 牛奶”)
    decorator->base.component->GetDesc(decorator->base.component, desc);
    // 扩展描述
    strncat(desc, " + 糖", MAX_DESC - strlen(desc) - 1);
}

// 加糖:扩展价格(基础价格 + 糖加价)
float sugar_get_price(CoffeeComponent* self) {
    SugarDecorator* decorator = (SugarDecorator*)self;
    // 转发获取被装饰组件的价格(如18元)
    return decorator->base.component->GetPrice(decorator->base.component) + decorator->add_price;
}

// 创建“加糖”装饰器
CoffeeComponent* create_sugar_decorator(CoffeeComponent* component) {
    SugarDecorator* decorator = (SugarDecorator*)malloc(sizeof(SugarDecorator));
    // 初始化抽象装饰器(绑定被装饰组件)
    decorator->base = *create_coffee_decorator(component);
    // 重写抽象装饰器的接口(扩展功能)
    decorator->base.base.GetDesc = sugar_get_desc;
    decorator->base.base.GetPrice = sugar_get_price;
    // 额外配置(糖的加价和描述)
    decorator->add_price = 2.0f;
    strncpy(decorator->add_desc, "糖", MAX_DESC);
    return (CoffeeComponent*)decorator;
}

// -------------------------- 测试代码(客户端) --------------------------
// 客户端:仅依赖抽象组件接口,无需区分基础咖啡和装饰器
void client_order(CoffeeComponent* coffee) {
    char desc[MAX_DESC] = {0};
    coffee->GetDesc(coffee, desc);
    printf("订单:%s,价格:%.1f元\n", desc, coffee->GetPrice(coffee));
}

int main() {
    // 1. 点一杯基础美式咖啡(无装饰)
    CoffeeComponent* americano = create_americano();
    printf("=== 基础订单 ===\n");
    client_order(americano);

    // 2. 美式 + 牛奶(装饰一次)
    CoffeeComponent* coffee_with_milk = create_milk_decorator(americano);
    printf("\n=== 装饰一次(加牛奶) ===\n");
    client_order(coffee_with_milk);

    // 3. 美式 + 牛奶 + 糖(嵌套装饰,动态添加多个职责)
    CoffeeComponent* coffee_with_milk_sugar = create_sugar_decorator(coffee_with_milk);
    printf("\n=== 嵌套装饰(加牛奶+糖) ===\n");
    client_order(coffee_with_milk_sugar);

    // 4. 美式 + 糖(单独装饰)
    CoffeeComponent* coffee_with_sugar = create_sugar_decorator(create_americano());
    printf("\n=== 单独装饰(加糖) ===\n");
    client_order(coffee_with_sugar);

    // 5. 资源释放(递归销毁,避免内存泄漏)
    coffee_with_milk_sugar->Destroy(coffee_with_milk_sugar);
    coffee_with_sugar->Destroy(coffee_with_sugar);

    return 0;
}

C++语言实现

同 C 语言:咖啡订单系统(抽象组件 Coffee、具体组件 Americano、抽象装饰器 CoffeeDecorator、具体装饰器 Milk/Sugar),支持动态组合装饰器。通过 “抽象基类 + 纯虚函数” 定义统一接口,抽象装饰器继承抽象组件并持有其智能指针(组合关系),代码更简洁、类型更安全。

关键要点

1.接口统一:抽象组件 Coffee 定义纯虚函数 GetDesc/GetPrice,抽象装饰器 CoffeeDecorator 继承 Coffee 并持有其指针,确保装饰器与被装饰对象接口一致。
2.多态核心:客户端通过 Coffee 智能指针调用方法,实际执行子类(Americano/Milk/Sugar)的实现,无需区分组件类型。
3.组合 + 转发:抽象装饰器 CoffeeDecorator 持有 std::shared_ptr,GetDesc/GetPrice 转发调用被装饰对象的方法;具体装饰器重写这两个方法,在转发基础上添加额外逻辑。
4.动态扩展:客户端可通过嵌套 std::make_shared 组合任意多个装饰器(如 Milk(Sugar(Americano()))),无需修改原类代码,符合开闭原则。
5.内存安全:智能指针 std::shared_ptr 自动管理对象生命周期,递归销毁嵌套的装饰器和基础组件,避免内存泄漏;虚析构函数确保子类析构被正确调用。
6.扩展灵活:新增配料(如 “奶泡”)时,只需新增 Foam 类继承 CoffeeDecorator 并实现 GetDesc/GetPrice,客户端可直接使用,无需修改现有代码。

#include <iostream>
#include <string>
#include <memory> // 智能指针(自动管理内存)

// -------------------------- 1. 抽象组件(Component):咖啡抽象基类 --------------------------
class Coffee {
public:
    virtual ~Coffee() = default; // 虚析构:确保子类析构被调用
    // 纯虚函数:统一接口(强制子类实现)
    virtual std::string GetDesc() const = 0;
    virtual float GetPrice() const = 0;
};

// -------------------------- 2. 具体组件(ConcreteComponent):基础咖啡(美式) --------------------------
class Americano : public Coffee {
public:
    std::string GetDesc() const override {
        return "美式咖啡";
    }

    float GetPrice() const override {
        return 15.0f; // 基础价格
    }
};

// -------------------------- 3. 抽象装饰器(Decorator):咖啡装饰器基类 --------------------------
class CoffeeDecorator : public Coffee { // 继承抽象组件,确保接口一致
public:
    // 构造函数:传入被装饰的咖啡组件(组合关系)
    explicit CoffeeDecorator(std::shared_ptr<Coffee> coffee) : coffee_(std::move(coffee)) {}

    // 转发调用被装饰组件的接口(子类可重写扩展)
    std::string GetDesc() const override {
        return coffee_->GetDesc();
    }

    float GetPrice() const override {
        return coffee_->GetPrice();
    }

protected:
    std::shared_ptr<Coffee> coffee_; // 持有被装饰组件(智能指针自动管理内存)
};

// -------------------------- 4. 具体装饰器(ConcreteDecorator):加牛奶 --------------------------
class Milk : public CoffeeDecorator {
public:
    explicit Milk(std::shared_ptr<Coffee> coffee) : CoffeeDecorator(std::move(coffee)) {}

    // 扩展描述:基础描述 + 牛奶
    std::string GetDesc() const override {
        return coffee_->GetDesc() + " + 牛奶";
    }

    // 扩展价格:基础价格 + 3元
    float GetPrice() const override {
        return coffee_->GetPrice() + 3.0f;
    }
};

// -------------------------- 5. 具体装饰器(ConcreteDecorator):加糖 --------------------------
class Sugar : public CoffeeDecorator {
public:
    explicit Sugar(std::shared_ptr<Coffee> coffee) : CoffeeDecorator(std::move(coffee)) {}

    // 扩展描述:基础描述 + 糖
    std::string GetDesc() const override {
        return coffee_->GetDesc() + " + 糖";
    }

    // 扩展价格:基础价格 + 2元
    float GetPrice() const override {
        return coffee_->GetPrice() + 2.0f;
    }
};

// -------------------------- 测试代码(客户端) --------------------------
// 客户端:仅依赖抽象组件(Coffee),无需区分基础咖啡和装饰器
void ClientOrder(const std::shared_ptr<Coffee>& coffee) {
    std::cout << "订单:" << coffee->GetDesc() << ",价格:" << coffee->GetPrice() << "元" << std::endl;
}

int main() {
    // 1. 基础订单:美式咖啡(无装饰)
    std::shared_ptr<Coffee> americano = std::make_shared<Americano>();
    std::cout << "=== 基础订单 ===" << std::endl;
    ClientOrder(americano);

    // 2. 装饰一次:美式 + 牛奶
    std::shared_ptr<Coffee> coffee_with_milk = std::make_shared<Milk>(americano);
    std::cout << "\n=== 装饰一次(加牛奶) ===" << std::endl;
    ClientOrder(coffee_with_milk);

    // 3. 嵌套装饰:美式 + 牛奶 + 糖(动态组合多个职责)
    std::shared_ptr<Coffee> coffee_with_milk_sugar = std::make_shared<Sugar>(coffee_with_milk);
    std::cout << "\n=== 嵌套装饰(加牛奶+糖) ===" << std::endl;
    ClientOrder(coffee_with_milk_sugar);

    // 4. 单独装饰:美式 + 糖
    std::shared_ptr<Coffee> coffee_with_sugar = std::make_shared<Sugar>(std::make_shared<Americano>());
    std::cout << "\n=== 单独装饰(加糖) ===" << std::endl;
    ClientOrder(coffee_with_sugar);

    return 0; // 智能指针自动销毁所有对象,无需手动释放
}

装饰模式核心总结(C vs C++)

对比维度	C 语言实现	C++ 语言实现接口模拟	结构体 + 函数指针	抽象基类 + 纯虚函数(原生多态)组合关系	结构体成员指针(手动绑定)	智能指针成员(自动管理)多态支持	手动绑定函数指针,类型转换风险高	虚函数表 + 编译期检查,多态安全内存管理	手动递归 Destroy + malloc/free	智能指针自动递归销毁,虚析构保障代码简洁度	需手动维护接口绑定和内存释放,繁琐	继承 + 多态 + STL 智能指针,代码简洁优雅扩展灵活性	支持扩展,但需手动实现装饰器结构体	新增子类即可扩展,完全符合开闭原则

设计原则

1.组合优于继承:装饰器通过组合持有组件,而非继承,降低耦合;
2.开闭原则:新增职责只需新增装饰器,无需修改原组件和现有装饰器;
3.接口一致:装饰器与被装饰对象实现同一接口,确保客户端透明操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值