《Head First 设计模式》例子的C++实现(3 装饰模式)
装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
装饰模式的特点是 装饰对象和真实对象有相同的接口。这样客户端对象就能以和真实对象相同的方式和装饰对象交互。
但是这种模式会导致设计中出现许多小类,如果过度使用,会使程序变得很复杂。
下面是代码:
///Beverage.h
#ifndef BEVERAGE_H
#define BEVERAGE_H
#include <QString>
class Beverage
{
public:
Beverage():description("Unknown Beverage") {}
virtual QString getDescription() {return description;}
virtual double cost() = 0;
protected:
QString description;
};
#endif // BEVERAGE_H
///CondimentDecorator.h
#ifndef CONDIMENTDECORATOR_H
#define CONDIMENTDECORATOR_H
#include "beverage.h"
class CondimentDecorator : public Beverage
{
public:
CondimentDecorator(){}
};
#endif // CONDIMENTDECORATOR_H
///DarkRoast.h
#ifndef DARKROAST_H
#define DARKROAST_H
#include "beverage.h"
class DarkRoast : public Beverage
{
public:
DarkRoast() {description = "Dark Roast Coffee";}
double cost() override {return 0.99;}
};
#endif // DARKROAST_H
///Decaf.h
#ifndef DECAF_H
#define DECAF_H
#include "beverage.h"
class Decaf : public Beverage
{
public:
Decaf(){description = "Decaf Coffee";}
double cost() override {return 1.;}
};
#endif // DECAF_H
///Espresso.h
#ifndef ESPRESSO_H
#define ESPRESSO_H
#include "beverage.h"
class Espresso : public Beverage
{
public:
Espresso() {description = "Espresso";}
double cost() override {return 1.99;}
};
#endif // ESPRESSO_H
///HouseBlend.h
#ifndef HOUSEBLEND_H
#define HOUSEBLEND_H
#include "beverage.h"
class HouseBlend : public Beverage
{
public:
HouseBlend(){description = "House Blend Coffee";}
double cost() override {return 0.89;}
};
#endif // HOUSEBLEND_H
///Milk.h
#ifndef MILK_H
#define MILK_H
#include "condimentdecorator.h"
class Milk : public CondimentDecorator
{
public:
Milk(Beverage *beverage);
QString getDescription();
double cost() override;
private:
Beverage *m_beverage;
};
#endif // MILK_H
#include "milk.h"
Milk::Milk(Beverage *beverage)
{
m_beverage = beverage;
// description = m_beverage->getDescription() + ", Milk";
}
QString Milk::getDescription()
{
return m_beverage->getDescription() + ", Milk";
}
double Milk::cost()
{
return 0.10 + m_beverage->cost();
}
///Mocha.h
#ifndef MOCHA_H
#define MOCHA_H
#include "condimentdecorator.h"
class Mocha : public CondimentDecorator
{
public:
Mocha(Beverage *beverage);
QString getDescription();
double cost() override;
private:
Beverage *m_beverage;
};
#endif // MOCHA_H
#include "mocha.h"
Mocha::Mocha(Beverage *beverage)
{
m_beverage = beverage;
// description = m_beverage->getDescription() + ", Mocha";
}
QString Mocha::getDescription()
{
return m_beverage->getDescription() + ", Mocha";
}
double Mocha::cost()
{
return 0.20 + m_beverage->cost();
}
///Soy.h
#ifndef SOY_H
#define SOY_H
#include "condimentdecorator.h"
class Soy : public CondimentDecorator
{
public:
Soy(Beverage *beverage);
QString getDescription();
double cost() override;
private:
Beverage *m_beverage;
};
#endif // SOY_H
#include "soy.h"
Soy::Soy(Beverage *beverage)
{
m_beverage = beverage;
// description = m_beverage->getDescription() + ", Soy";
}
QString Soy::getDescription()
{
return m_beverage->getDescription() + ", Soy";
}
double Soy::cost()
{
return 0.15 + m_beverage->cost();
}
///Whip.h
#ifndef WHIP_H
#define WHIP_H
#include "condimentdecorator.h"
class Whip : public CondimentDecorator
{
public:
Whip(Beverage *beverage);
QString getDescription();
double cost() override;
private:
Beverage *m_beverage;
};
#endif // WHIP_H
#include "whip.h"
Whip::Whip(Beverage *beverage)
{
m_beverage = beverage;
// description = m_beverage->getDescription() + ", Whip";
}
QString Whip::getDescription()
{
return m_beverage->getDescription() + ", Whip";
}
double Whip::cost()
{
return 0.10 + m_beverage->cost();
}
#include <QCoreApplication>
#include <QDebug>
#include "espresso.h"
#include "darkroast.h"
#include "houseblend.h"
#include "milk.h"
#include "mocha.h"
#include "soy.h"
#include "whip.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Beverage *beverage = new Espresso();
qDebug() << beverage->getDescription() << " $" << beverage->cost();
Beverage *beverage2 = new DarkRoast();
beverage2 = new Mocha(beverage2);
beverage2 = new Mocha(beverage2);
beverage2 = new Whip(beverage2);
qDebug() <<beverage2->getDescription() << " $" << beverage2->cost();
Beverage *beverage3 = new HouseBlend();
beverage3 = new Soy(beverage3);
beverage3 = new Mocha(beverage3);
beverage3 = new Whip(beverage3);
qDebug() << beverage3->getDescription() << " $" << beverage3->cost();
return a.exec();
}
这个小例子就能将装饰模式的优缺点都体现出来了。用了装饰模式 main 函数的代码非常的简洁。但是代价是多出来了将近10个小类。
我个人不推荐使用这种设计模式。