c++设计模式:装饰者模式(Decorator Pattern)

摘要:
定义:装饰器模式动态地将责任附加到对象。为了扩展功能,装饰器提供了一种更灵活的继承替代方案。场景:当我们购买咖啡时,我们可以要求添加各种调味品,如蒸牛奶、豆浆、摩卡咖啡或牛奶泡沫。咖啡店会根据添加的调味品收取不同的费用,因此我们在设计订单系统时需要考虑这些调味品。客户有不同的需求。如果我们为每个公式声明一个类,那么系统的维护将非常困难。装饰器模式将派上用场。我们可以

定义:

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

场景:

我们购买咖啡的时候,可以要求在其中加入各种调料,例如:蒸奶、豆浆、摩卡或覆盖奶泡,而咖啡店也会根据所加入的调料收取不同的费用,所以当我们设计订单系统的时候就需要考虑到这些调料部分啦。顾客的需求不一,如果我们针对每种配方都声明一个类得话,系统的维护将会十分头疼。此时装饰者模式就派上用场啦。我们可以根据顾客的需要动态的扩展顾客定制的咖啡,让其加上不同的调料,最终计算出顾客所需缴纳的费用。它的实现有点类似于递归,在实际使用的时候可以慢慢体会。

类图:

c++设计模式:装饰者模式(Decorator Pattern)第1张

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 设计模式》

免责声明:文章转载自《c++设计模式:装饰者模式(Decorator Pattern)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇ubuntu16.04 安装 nginx 服务器开启9008端口进入深刷模式下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

【C#写日志两个简单方法】

方法一:以日期为日志文件名. public void WriteLog(stringmsg) { string filePath = AppDomain.CurrentDomain.BaseDirectory + "Log"; if (!Directory.Exists(filePath)) {...

SpringBoot请求处理-常用参数注解使用

PathVariable RequestBody @RestController public class ParameterTestController { /** * 数据绑定:页面提交的请求数据(GET、POST)都可以和对象属性进行绑定 * @param person * @return */...

HashMap实现缓存

package com.cache; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; pub...

使用CefSharp跳转页面不弹出页面:

using CefSharp; using CefSharp.Wpf; namespace Common.Control { internal class CefSharpOpenPageSelf : ILifeSpanHandler { public bool DoClose(IWebBrowser browserCont...

Spring Security 实战干货:玩转自定义登录

文章目录 1. 前言 2. form 登录的流程 3. Spring Security 中的登录 4. HttpSecurity 中的 form 表单登录 4.1 FormLoginConfigurer 5. Spring Security 聚合登录 实战 5.1 简单需求 6. 多种登录方式的简单实现 6.1 登录方式定义 6.2 定义前置处理器...

HashTable,Dictionary,ConcurrentDictionary 的应用场景,区别,用法统计

https://www.cnblogs.com/yinrq/p/5584885.html 一、HashTable HashTable表示键/值对的集合。在.NET Framework中,Hashtable是System.Collections命名空间提供的一个容器,用于处理和表现类似key-value的键值对,其中key通常可用来快速查找,同时key是区分...