定义:
装饰者模式动态的将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
场景:
我们购买咖啡的时候,可以要求在其中加入各种调料,例如:蒸奶、豆浆、摩卡或覆盖奶泡,而咖啡店也会根据所加入的调料收取不同的费用,所以当我们设计订单系统的时候就需要考虑到这些调料部分啦。顾客的需求不一,如果我们针对每种配方都声明一个类得话,系统的维护将会十分头疼。此时装饰者模式就派上用场啦。我们可以根据顾客的需要动态的扩展顾客定制的咖啡,让其加上不同的调料,最终计算出顾客所需缴纳的费用。它的实现有点类似于递归,在实际使用的时候可以慢慢体会。
类图:
c++代码如下:
不使用指针版本:
#include <iostream>
#include <string>
using namespace std;
class Beverage
{
public:
virtual ~Beverage() {};
virtual string getDescription(); // 必须是虚函数,否则会造成后期使用时描述显示不正确
virtual double cost() = 0;
protected:
string m_description;
};
class CondimentDecorator:public Beverage
{
public:
virtual string getDescription() = 0;
};
class Espresso:public Beverage
{
public:
Espresso();
double cost();
};
class HouseBlend:public Beverage
{
public:
HouseBlend();
double cost();
};
class DarkRoast:public Beverage
{
public:
DarkRoast();
double cost();
};
class Decaf:public Beverage
{
public:
Decaf();
double cost();
};
class Mocha:public CondimentDecorator
{
public:
Mocha(Beverage* pBeverage);
string getDescription();
double cost();
protected:
Beverage* m_pBeverage;
};
class Milk:public CondimentDecorator
{
public:
Milk(Beverage* pBeverage);
string getDescription();
double cost();
protected:
Beverage* m_pBeverage;
};
class Soy:public CondimentDecorator
{
public:
Soy(Beverage* pBeverage);
string getDescription();
double cost();
protected:
Beverage* m_pBeverage;
};
class Whip:public CondimentDecorator
{
public:
Whip(Beverage* pBeverage);
string getDescription();
double cost();
protected:
Beverage* m_pBeverage;
};
string Beverage::getDescription()
{
return m_description;
}
Espresso::Espresso()
{
m_description = "Espresso";
}
double Espresso::cost()
{
return 1.99;
}
HouseBlend::HouseBlend()
{
m_description = "House Blend Coffee";
}
double HouseBlend::cost()
{
return 0.89;
}
DarkRoast::DarkRoast()
{
m_description = "Dark Roast Coffee";
}
double DarkRoast::cost()
{
return 0.99;
}
Decaf::Decaf()
{
m_description = "Decaf Coffee";
}
double Decaf::cost()
{
return 1.05;
}
Mocha::Mocha(Beverage* pBeverage)
{
m_pBeverage = pBeverage;
}
string Mocha::getDescription()
{
return m_pBeverage->getDescription() + " + Mocha";
}
double Mocha::cost()
{
return 0.20 + m_pBeverage->cost();
}
Milk::Milk(Beverage* pBeverage)
{
m_pBeverage = pBeverage;
}
string Milk::getDescription()
{
return m_pBeverage->getDescription() + " + Milk";
}
double Milk::cost()
{
return 0.10 + m_pBeverage->cost();
}
Soy::Soy(Beverage* pBeverage)
{
m_pBeverage = pBeverage;
}
string Soy::getDescription()
{
return m_pBeverage->getDescription() + " + Soy";
}
double Soy::cost()
{
return 0.15 + m_pBeverage->cost();
}
Whip::Whip(Beverage* pBeverage)
{
m_pBeverage = pBeverage;
}
string Whip::getDescription()
{
return m_pBeverage->getDescription() + " + Whip";
}
double Whip::cost()
{
return 0.10 + m_pBeverage->cost();
}
int main()
{
Espresso espresso;
cout << espresso.getDescription() << " $" << espresso.cost() << endl;
DarkRoast darkRoast;
Mocha mocha1(&darkRoast);
Mocha mocha2(&mocha1);
Whip whip1(&mocha2);
cout << whip1.getDescription() << " $" << whip1.cost() << endl;
HouseBlend houseBlend;
Soy soy1(&houseBlend);
Mocha mocha3(&soy1);
Whip whip2(&mocha3);
cout << whip2.getDescription() << " $" << whip2.cost() << endl;
return 0;
}
使用指针版本:
#include <iostream>
#include <string>
using namespace std;
class Beverage
{
public:
virtual ~Beverage() {};
virtual string getDescription();
virtual double cost() = 0;
protected:
string m_description;
};
class CondimentDecorator:public Beverage
{
public:
virtual string getDescription() = 0;
};
class Espresso:public Beverage
{
public:
Espresso();
double cost();
};
class HouseBlend:public Beverage
{
public:
HouseBlend();
double cost();
};
class DarkRoast:public Beverage
{
public:
DarkRoast();
double cost();
};
class Decaf:public Beverage
{
public:
Decaf();
double cost();
};
class Mocha:public CondimentDecorator
{
public:
Mocha(Beverage* pBeverage);
~Mocha();
string getDescription();
double cost();
protected:
Beverage* m_pBeverage;
};
class Milk:public CondimentDecorator
{
public:
Milk(Beverage* pBeverage);
~Milk();
string getDescription();
double cost();
protected:
Beverage* m_pBeverage;
};
class Soy:public CondimentDecorator
{
public:
Soy(Beverage* pBeverage);
~Soy();
string getDescription();
double cost();
protected:
Beverage* m_pBeverage;
};
class Whip:public CondimentDecorator
{
public:
Whip(Beverage* pBeverage);
~Whip();
string getDescription();
double cost();
protected:
Beverage* m_pBeverage;
};
string Beverage::getDescription()
{
return m_description;
}
Espresso::Espresso()
{
m_description = "Espresso";
}
double Espresso::cost()
{
return 1.99;
}
HouseBlend::HouseBlend()
{
m_description = "House Blend Coffee";
}
double HouseBlend::cost()
{
return 0.89;
}
DarkRoast::DarkRoast()
{
m_description = "Dark Roast Coffee";
}
double DarkRoast::cost()
{
return 0.99;
}
Decaf::Decaf()
{
m_description = "Decaf Coffee";
}
double Decaf::cost()
{
return 1.05;
}
Mocha::Mocha(Beverage* pBeverage)
{
m_pBeverage = pBeverage;
}
Mocha::~Mocha()
{
delete m_pBeverage;
}
string Mocha::getDescription()
{
return m_pBeverage->getDescription() + " + Mocha";
}
double Mocha::cost()
{
return 0.20 + m_pBeverage->cost();
}
Milk::Milk(Beverage* pBeverage)
{
m_pBeverage = pBeverage;
}
Milk::~Milk()
{
delete m_pBeverage;
}
string Milk::getDescription()
{
return m_pBeverage->getDescription() + " + Milk";
}
double Milk::cost()
{
return 0.10 + m_pBeverage->cost();
}
Soy::Soy(Beverage* pBeverage)
{
m_pBeverage = pBeverage;
}
Soy::~Soy()
{
delete m_pBeverage;
}
string Soy::getDescription()
{
return m_pBeverage->getDescription() + " + Soy";
}
double Soy::cost()
{
return 0.15 + m_pBeverage->cost();
}
Whip::Whip(Beverage* pBeverage)
{
m_pBeverage = pBeverage;
}
Whip::~Whip()
{
delete m_pBeverage;
}
string Whip::getDescription()
{
return m_pBeverage->getDescription() + " + Whip";
}
double Whip::cost()
{
return 0.10 + m_pBeverage->cost();
}
int main()
{
Beverage* pBeverage = new Espresso();
cout << pBeverage->getDescription() << " $" << pBeverage->cost() << endl;
Beverage* pBeverage2 = new DarkRoast();
pBeverage2 = new Mocha(pBeverage2);
pBeverage2 = new Mocha(pBeverage2);
pBeverage2 = new Whip(pBeverage2);
cout << pBeverage2->getDescription() << " $" << pBeverage2->cost() << endl;
Beverage* pBeverage3 = new HouseBlend();
pBeverage3 = new Soy(pBeverage3);
pBeverage3 = new Mocha(pBeverage3);
pBeverage3 = new Whip(pBeverage3);
cout << pBeverage3->getDescription() << " $" << pBeverage3->cost() << endl;
delete pBeverage;
delete pBeverage2;
delete pBeverage3;
return 0;
}
运行后结果如下:
Espresso $1.99
Dark Roast Coffee + Mocha + Mocha + Whip $1.49
House Blend Coffee + Soy + Mocha + Whip $1.34
参考图书:《Head First 设计模式》