原则

  • 装饰者和主题继承同一个基类(主要是利用继承来达到“类型匹配”的目的,而不是利用继承获得行为)
  • 可以用一个或者多个装饰者包装主体对象
  • 装饰者内部保存主体对象的引用或者指针
  • 装饰者可以动态的包装主体对象,即运行时改变主体对象行为

经典类图

类图说明:

Component
对象的接口类,定义装饰对象和被装饰对象的共同接口*


ConcreteComponent
被装饰对象的类定义:属于具体实现的类


Decorator
装饰对象的抽象类,持有一个具体的被修饰对象,并实现接口类继承的公共接口;


ConcreteDecorator
具体的装饰器,负责往被装饰对象添加额外的功能;

精髓

装饰器模式主要是为某个东西附加不同的功能,抽象装饰者和主体继承同一个类(非常关键)。如下例子:

有一块烧饼 (烧饼是主体)

  • 夹肉:变成肉夹馍 (夹肉的动作就是装饰)
  • 夹菜:变成菜夹馍 (夹菜的动作就是装饰)

其中菜,和肉作为不同的装饰,将馍变成不同口感的食物,抽象来说应继承同一个抽象类,它们都是具体的实现。
也可以认为:

  1. 主体可能只有一个
  2. 装饰可以有多个,装饰可以任意组合

装饰器的应用场景

  1. 需要对现有类附加职责,但又不想以继承方式扩充时
  2. 需要对现有的一组基本功能进行排列组合而产生非常多的功能时
  3. 当对象的功能需要动态的添加、撤销时

代码实现(咖啡封装)

class Beverage
{
protected:
    QString _description = "Unknow";
    double _cost = 0;

public:
    virtual double cost() const { return _cost; };
    virtual QString description() const { return _description; };
};

//装饰者基类
class CondimentDecorator : public Beverage
{
protected:
    QSharedPointer<Beverage> _beverage;

public:
    CondimentDecorator(QSharedPointer<Beverage>& beverage) : _beverage(beverage)
    {
        _description = "Decorator";
    }
};

//浓咖啡主体
class Espresso : public Beverage
{
public:
    Espresso()
    {
        _description = "Espresso";
        _cost = 1.99;
    }
};

class Mocha : public CondimentDecorator
{
public:
    Mocha(QSharedPointer<Beverage>& beverage) : CondimentDecorator(beverage)
    {
        _description = "Mocha";
        _cost = .99;
    }

    QString description() const override { return _beverage->description() + _description; }
    double cost() const override { return _beverage->cost() + _cost; };
};

int main(int argc, char* argv[])
{
    QApplication a(argc, argv);
    {
        QSharedPointer<Beverage> coffe(new Espresso());
        qDebug() << coffe->description();
        qDebug() << coffe->cost();

        QSharedPointer<Beverage> mochaCoffe(new Mocha(coffe));
        qDebug() << mochaCoffe->description();
        qDebug() << mochaCoffe->cost();
    }
    return a.exec();
}
作者:admin  创建时间:2023-12-05 14:33
最后编辑:admin  更新时间:2025-02-10 11:18