设计模式四:装饰模式(Decorator Pattern)

装饰模式是一种结构型设计模式,它允许你动态地给一个对象添加额外的职责,相比继承更加灵活。

1. 模式定义

装饰模式:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比生成子类更为灵活。

2. 模式结构

主要角色:

  • Component(抽象构件):定义对象的接口,可以给这些对象动态添加职责

  • ConcreteComponent(具体构件):定义具体的对象,可以给它添加职责

  • Decorator(抽象装饰类):继承/实现Component,并包含一个Component的引用

  • ConcreteDecorator(具体装饰类):向构件添加具体职责

代码:

复制代码
#include <iostream>
#include <string>

// 抽象构件
class Beverage {
public:
    virtual ~Beverage() = default;
    virtual std::string getDescription() const = 0;
    virtual double cost() const = 0;
};

// 具体构件
class Espresso : public Beverage {
public:
    std::string getDescription() const override {
        return "Espresso";
    }
    
    double cost() const override {
        return 1.99;
    }
};

// 抽象装饰类
class CondimentDecorator : public Beverage {
protected:
    Beverage* beverage;
public:
    explicit CondimentDecorator(Beverage* beverage) : beverage(beverage) {}
    virtual ~CondimentDecorator() { delete beverage; }
    
    std::string getDescription() const override = 0;
};

// 具体装饰类A
class Milk : public CondimentDecorator {
public:
    explicit Milk(Beverage* beverage) : CondimentDecorator(beverage) {}
    
    std::string getDescription() const override {
        return beverage->getDescription() + ", Milk";
    }
    
    double cost() const override {
        return beverage->cost() + 0.20;
    }
};

// 具体装饰类B
class Mocha : public CondimentDecorator {
public:
    explicit Mocha(Beverage* beverage) : CondimentDecorator(beverage) {}
    
    std::string getDescription() const override {
        return beverage->getDescription() + ", Mocha";
    }
    
    double cost() const override {
        return beverage->cost() + 0.30;
    }
};

// 使用示例
int main() {
    // 创建基础饮料
    Beverage* beverage = new Espresso();
    std::cout << beverage->getDescription() << " $" << beverage->cost() << std::endl;
    
    // 用装饰类包装
    Beverage* beverage2 = new Milk(beverage);
    beverage2 = new Mocha(beverage2);  // 再次装饰
    
    std::cout << beverage2->getDescription() << " $" << beverage2->cost() << std::endl;
    
    delete beverage2;  // 会递归删除所有装饰对象
    
    return 0;
}

uml结构

3. 模式特点

优点:

  1. 比继承更灵活:动态添加或撤销功能

  2. 避免子类膨胀:通过组合而非继承扩展功能

  3. 符合开闭原则:对扩展开放,对修改关闭

缺点:

  1. 会产生许多小对象:增加系统复杂度

  2. 多层装饰时调试困难:需要逐层检查

4. 应用场景

  1. 扩展单个对象的功能,而不影响其他对象

  2. 动态透明地添加职责,可以随时撤销

  3. 不适合用子类扩展的情况(如子类数量爆炸)

5. 装饰模式 vs 继承

特性 装饰模式 继承
扩展方式 动态组合 静态编译时确定
灵活性 高,可运行时调整 低,编译时固定
对象关系 组合关系 父子关系
类数量 装饰类数量较少 可能导致子类爆炸

装饰模式是扩展对象功能的一种灵活方式,特别适合在运行时动态添加或修改对象行为的场景。