(8)装饰器模式

装饰器模式(Decorator Pattern) 是一种结构型设计模式,它允许你动态地给一个对象添加额外的功能或行为,而无需修改其原始类。它通过将对象包装在“装饰器”类中来实现功能的扩展,比继承更灵活。
核心思想
 - 动态扩展功能,在运行时添加或移除功能,比静态继承更灵活。
 - 避免类爆炸,如果用继承实现多种组合,类数量会指数级增长;装饰器可以组合使用。
 - 符合开闭原则,对扩展开放(加装饰器),对修改关闭(不改原类)。
 - 职责分离,每个装饰器只负责一项功能,代码更清晰。

缺点
 - 增加了系统的复杂性(更多小类)。
 - 调试时堆栈可能变深。
 - 客户端可能需要创建复杂的装饰链。
代码示例
示例:咖啡店系统
基础咖啡(Espresso)价格 20 元;
添加牛奶(Milk)+5 元;
添加糖(Sugar)+3 元;
添加牛奶(Milk)+5 元 + 添加糖(Sugar)+3 元;
使用装饰器动态计算价格。
#include <iostream>
#include <string>
#include <memory>

// 使用别名简化代码
using std::string;
using std::unique_ptr;

// ==================== 组件接口 ====================
class Coffee {
public:
    virtual ~Coffee() = default;
    virtual double cost() const = 0;
    virtual string description() const = 0;
};

// ==================== 具体组件:基础咖啡 ====================
class Espresso : public Coffee {
public:
    double cost() const override {
        return 20.0;
    }

    string description() const override {
        return "浓缩咖啡";
    }
};

// ==================== 装饰器基类 ====================
class CoffeeDecorator : public Coffee {
protected:
    unique_ptr<Coffee> coffee;  // 使用智能指针持有被装饰对象

public:
    // 通过移动语义接收 unique_ptr
    CoffeeDecorator(unique_ptr<Coffee> c) : coffee(std::move(c)) {}

    // 默认析构即可,unique_ptr 自动清理
    virtual ~CoffeeDecorator() = default;

    double cost() const override {
        return coffee->cost();
    }

    string description() const override {
        return coffee->description();
    }
};

// ==================== 具体装饰器1:加牛奶 ====================
class Milk : public CoffeeDecorator {
public:
    explicit Milk(unique_ptr<Coffee> c) : CoffeeDecorator(std::move(c)) {}

    double cost() const override {
        return coffee->cost() + 5.0;  // 原价 +5
    }

    string description() const override {
        return coffee->description() + " + 牛奶";
    }
};

// ==================== 具体装饰器2:加糖 ====================
class Sugar : public CoffeeDecorator {
public:
    explicit Sugar(unique_ptr<Coffee> c) : CoffeeDecorator(std::move(c)) {}

    double cost() const override {
        return coffee->cost() + 3.0;  // 原价 +3
    }

    string description() const override {
        return coffee->description() + " + 糖";
    }
};
// ==================== 测试 ====================
int main() {
    // 1. 一杯基础咖啡
    auto c1 = std::make_unique<Espresso>();
    std::cout << c1->description() << " 价格:" << c1->cost() << "元\n\n";

    // 2. 咖啡 + 牛奶
    auto c2 = std::make_unique<Milk>(std::make_unique<Espresso>());
    std::cout << c2->description() << " 价格:" << c2->cost() << "元\n\n";

    // 3. 咖啡 + 牛奶 + 糖
    auto c3 = std::make_unique<Sugar>(
                  std::make_unique<Milk>(
                      std::make_unique<Espresso>()
                  )
              );
    std::cout << c3->description() << " 价格:" << c3->cost() << "元\n";

    // 不需要手动 delete!析构时自动释放
    return 0;
}
进阶-使用模板
// ==================== 模板装饰器基类 ====================
// 所有装饰器继承自这个模板
template<typename T>
class CoffeeDecorator : public Coffee, public T {
public:
    // 继承被装饰对象,并转发所有接口
    explicit CoffeeDecorator(unique_ptr<T> coffee)
        : coffee(std::move(coffee)) {}

protected:
    unique_ptr<T> coffee;  // 持有被装饰的对象
};
// ==================== 具体装饰器1:加牛奶 ====================
class Milk : public CoffeeDecorator<Coffee> {
public:
    using CoffeeDecorator::CoffeeDecorator;  // 继承构造函数

    double cost() const override {
        return coffee->cost() + 5.0;
    }

    string description() const override {
        return coffee->description() + " + 牛奶";
    }
};

// ==================== 具体装饰器2:加糖 ====================
class Sugar : public CoffeeDecorator<Coffee> {
public:
    using CoffeeDecorator::CoffeeDecorator;

    double cost() const override {
        return coffee->cost() + 3.0;
    }

    string description() const override {
        return coffee->description() + " + 糖";
    }
};

// ==================== 具体装饰器3:加奶油 ====================
class Whip : public CoffeeDecorator<Coffee> {
public:
    using CoffeeDecorator::CoffeeDecorator;

    double cost() const override {
        return coffee->cost() + 4.0;
    }

    string description() const override {
        return coffee->description() + " + 奶油";
    }
};
posted @ 2018-12-12 22:35  osbreak  阅读(150)  评论(0)    收藏  举报