Qt-装饰者模式

1. 定义装饰者模式

    装饰者模式动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。

  • 装饰者和被装饰对象有共同的超类型
  • 你可以用一个或多个装饰者包装一个对象。
  • 既然装饰者和被装饰对象有相同的类型,所以在任何需要原始对象(被包装)的场合,可以用装饰过的对象代替它。
  • 装饰者可以在所委托被装饰者的行为之前与/或之后,加上自己的行为,以达到特定的目的。
  • 对象可以在任何时候被装饰,所以可以在运行时动态地、不限量地用你喜欢的装饰者来装饰对象。


2. 类图

Qt-装饰者模式_第1张图片


3. 举例说明

    在购买咖啡的时候,我们可以加入各种配料,例如:牛奶(milk)、摩卡(mocha)、奶泡(whip)

你加的东西不一样收取的费用就不一样。

   这个时候你肯定会想,我们按照东西给钱就就好了。我要一杯咖啡+牛奶+摩卡 就给这三者相加的钱就好了。 实际生活中情况也是这个样子。

如果使用装饰着模式我们需要怎么做呢?

解决方式:

    我们以饮料为主体(超类),然后在运行时以配料来装饰饮料。比方说顾客想要 摩卡(mocha) 和 奶泡(whip) 的浓咖啡(Espresso),那么,要做的是:拿一个浓咖啡(Espresso)对象,以摩卡(Mocha)对象装饰它,以奶泡(whip)对象装饰它.


根据上面类图,我们设计关于 咖啡-配料 的关系类图

Qt-装饰者模式_第2张图片


4 具体实现代码

由于代码量少,所有函数体就写在.h文件里面了,就建立cpp文件了。

首先实现超类接口:

Beverage.h

Beverage 是一个抽象类,有两个方法: setDescription()和cost()

setDescription() 已经实现,但是cost()必须在子类中实现。

#ifndef BEVERAGE
#define BEVERAGE

#include 

class Beverage
{
public:
    Beverage(QString str = "Unknow Beverage")
        :description(str){}

    virtual QString getDescription()
    {
        return description;
    }

    virtual double cost(){return 0;}

private:
    QString description;
};

#endif // BEVERAGE

CondimentDecorator.h

所有的配料装饰者都必须重新实现setDescription()方法。

#ifndef CONDIMENTDECORATOR
#define CONDIMENTDECORATOR

#include "Beverage.h"

class CondimentDecorator : public Beverage
{
public:
    QString getDescription(){return "";}
};

#endif // CONDIMENTDECORATOR

写饮料代码

现在,已经有了基类,让我们开始实现一些饮料吧!先从浓缩咖啡(Espresso)开始。我们需要设置饮料的描述,和它的价格。

Espresso.h

#ifndef ESPRESSO
#define ESPRESSO

#include "Beverage.h"

class Espresso : public Beverage
{
public:

    Espresso():Beverage("Espresso"){}

    double cost()
    {
        return 1.99;
    }
};

#endif // ESPRESSO

同理

HouseBlend.h

#ifndef HOUSEBLEND
#define HOUSEBLEND

#include "Beverage.h"

class HouseBlend : public Beverage
{
public:
    HouseBlend():Beverage("HouseBlend Coffee"){}

    double cost()
    {
        return 0.89;
    }
};

#endif // HOUSEBLEND

写调料代码

   如果你回头去看看装饰者模式的类图,你会发现我们已经完成了抽闲组件(Beverage),有了具体组件(Espresso、HouseBlend),也有了抽象装饰着(CondimentDecorator)。现在,我们就来实现具体的装饰者,先从摩卡开始。

Mocha.h

#ifndef MOCHA
#define MOCHA

#include "CondimentDecorator.h"

class Mocha : public CondimentDecorator
{
public:
    Mocha(Beverage* beve)
    {
        beverage = beve;  // 想办法让被装饰者被记录到实例变量中。这里做法是:把饮料当作构造器的参数,
                         // 再由构造器将此饮料记录在实例变量中。
    }

    QString getDescription()
    {
        return beverage->getDescription()+", Mocha"; // 描述:帮助这杯饮料都有什么材料
    }

    double cost()
    {
        return 0.20 + beverage->cost();    // 0.2是摩卡的价钱,加上被装饰的价钱
    }
private:
    Beverage* beverage;
};

#endif // MOCHA

其他配料同理:

Whip.h

#ifndef WHIP
#define WHIP

#include "CondimentDecorator.h"

class Whip : public CondimentDecorator
{
public:
    Whip(Beverage* beve)
    {
        beverage = beve;
    }

    QString getDescription()
    {
        return beverage->getDescription()+", Whip";
    }

    double cost()
    {
        return 0.15 + beverage->cost();
    }
private:
    Beverage* beverage;
};

#endif // WHIP

好了,其他配料自己写吧,都是一样的。

现在开始点餐:

main.cpp

#include 
#include 

#include "HouseBlend.h"
#include "Espresso.h"
#include "Beverage.h"
#include "Mocha.h"
#include "Whip.h"
#include "Soy.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    // 点一杯 Espresso 什么都不加
    Beverage * beverage = new Espresso();
    qDebug() << beverage->getDescription() << beverage->cost();

    // 点一杯 HouseBlend 加whip 和 Mocha
    Beverage * beverage2 = new HouseBlend();
    beverage2 = new Mocha(beverage2);
    beverage2 = new Whip(beverage2);
    qDebug() << beverage2->getDescription() << beverage2->cost();

    // 点一杯 HouseBlend 加whip 和 Mocha Soy
    Beverage * beverage3 = new HouseBlend();
    beverage3 = new Mocha(beverage2);
    beverage3 = new Whip(beverage2);
    beverage3 = new Soy(beverage2);
    qDebug() << beverage3->getDescription() << beverage3->cost();


    return a.exec();
}
先来杯浓缩咖啡,

再来杯综合咖啡 + 摩卡 + 奶泡

Qt-装饰者模式_第3张图片

我们要的结果出来了。接下来总结下。

5. 总结

   装饰者模式,我们使用的00原则:

    多组合,少继承。

    对扩展开发,对修改关闭。

   多组合可以很好想,多种配料组合起来的饮料。我们只需要把我们想要的配料,动态的装饰在我们的饮料上。就会得到我们想要的。

   对扩展开发,对修改关闭,其实观察者模式也是这样的。我们使用装饰着,相加什么配料,只需要去增加我们配料代码就好了。原来的代码我们不需要修改,随意的扩展 给咖啡加点  醋啊 、酱油啊、盐什么的。


ps: 以上内容学习 Head First设计模式 + 百度百科

你可能感兴趣的:(Qt设计模式)