这是个人学习编程模式的系列学习笔记第三篇。
采用Qt Creator进行编写,但尽量采用C++基础语法。
装饰模式(Decorator):动态地给一个对象增加一些额外的职责,就增加的功能来说,Decorator模式相比生成子类更加灵活。
个人理解,就是定义一个抽象类功能接口,然后具体类和装饰类都继承这个接口。装饰类通过继承实现不同的装饰功能子类,通过对具体类装饰不同的装饰功能子类实现对具体类的功能增加。具体的实现机制是在装饰类中添加抽象类指针,在装饰功能子类运行新增的功能,然后调用父类(装饰类)的功能接口去调用具体类的功能接口。有点类似递归,可以对具体类装饰多个装饰功能类,最后统一执行(执行顺序取决于装饰功能类是先运行新功能还是先调用原有功能)。
描述有点抽象。具体类之间的关系可以参考下面的UML图。
场景描述
有一家所谓的保健品生成厂家,生产各种保健品(比如大力丸、磁力杯等),由于是保健品,具体的功能就根据需要来定了,反正就是这么一说,按需要,啥病都能治。需要啥疗效就增加啥疗效说明,方便快捷(比如延迟寿命、治疗高血压、治疗癌症等)。按需生产,需要啥样功能的产品定制生产。
设计思路
定义一个产品类(Product,抽象类)作为疗效接口。
具体的产品类继承这个产品类。并实现这个疗效的接口(只实现基础的产品说明,还没添加疗效说明)。
定义一个添加疗效说明的装饰类,这个类(Addeffect,抽象类)也继承产品类,并实现这个疗效的接口(这个接口实现对具体产品类的疗效接口的调用,用于添加具体的产品说明。因此这个类需要有一个属性是指向产品类(抽象类)的指针,用于指示调用具体什么产品的产品说明)。
具体的装饰类用于添加具体的疗效说明,然后调用父类的疗效功能接口添加基础产品说明。
可以根据需求对产品定制(装饰)不同的功能装饰类(添加不同的疗效说明)。
这个样式可以有变化,比如只有一种保健产品,只是根据需求定制不同的疗效说明,则产品类可以不是抽象类,直接实现具体的产品功能(就没有子类继承了)。
还定义了一个工厂类,用于创建不同的产品和添加不同的疗效说明(简单工厂模式)。
为实验前后端分离,定义了客户端类,用于处理用户输入(产品类型、品牌、疗效)和输出(最终按需定制的保健品)。
UML图

代码
由于添加了客户端和工厂类,在主程序中还添加了简单的用户输入错误处理,代码略微复杂。但这部分同装饰模式没有什么关系,如果只是试验装饰模式,可以不用Factory类和Client类。在main.cpp中通过以下简单代码来测试:
#include "product.h"
#include "daliwan.h"
#include "cilibei.h"
#include "addeffect.h"
#include "prolonglife.h"
#include "treatingcancer.h"
#include "treatingthypertension.h"
#include <iostream>
using namespace std;
int main()
{
Product* product = new DaLiWan("智商税");
AddEffect* longlife = new ProlongLife(product);
AddEffect* cancer = new TreatingCancer(longlife);
AddEffect* hypertension = new TreatingtHypertension(cancer);
hypertension->effect();
delete hypertension;
delete cancer;
delete longlife;
delete product;
return 0;
}
以下为完整代码:
Product类
product.h
class Product
{
public:
Product();
~Product();
virtual void effect() = 0;
};
product.cpp
Product::Product()
{
}
Product::~Product()
{
}
DaLiWan类
daliwan.h
#include "product.h"
#include <iostream>
using namespace std;
class DaLiWan : public Product
{
private:
string m_brand;
public:
DaLiWan(string name);
~DaLiWan();
void effect();
};
daliwan.cpp
#include "daliwan.h"
#include <iostream>
using namespace std;
DaLiWan::DaLiWan(string name)
{
m_brand = name;
}
DaLiWan::~DaLiWan()
{
}
void DaLiWan::effect()
{
cout<<m_brand<<"牌大力丸是一个淀粉做的药丸,它能:";
}
CiLiBei类
cilibei.h
#include "product.h"
#include <iostream>
using namespace std;
class CiLiBei : public Product
{
private:
string m_brand;
public:
CiLiBei(string name);
~CiLiBei();
void effect();
};
cilibei.cpp
#include "cilibei.h"
#include <iostream>
using namespace std;
CiLiBei::CiLiBei(string name)
{
m_brand = name;
}
CiLiBei::~CiLiBei()
{
}
void CiLiBei::effect()
{
cout<<m_brand<<"牌磁力杯是一个有磁铁的水杯,它能:";
}
AddEffect类
addeffect.h
#include "product.h"
class AddEffect : public Product
{
private:
Product * m_product;
public:
AddEffect(Product *product);
~AddEffect();
virtual void effect();
};
addeffect.cpp
#include "addeffect.h"
AddEffect::AddEffect(Product *product)
{
m_product = product;
}
AddEffect::~AddEffect()
{
}
void AddEffect::effect()
{
m_product->effect();
}
ProlongLife类
prolonglife.h
#include "addeffect.h"
class ProlongLife : public AddEffect
{
private:
void addNewEffect();
public:
ProlongLife(Product * product);
~ProlongLife();
void effect();
};
prolonglife.cpp
#include "prolonglife.h"
#include <iostream>
using namespace std;
void ProlongLife::addNewEffect()
{
cout<<"延年益寿 ";
}
ProlongLife::ProlongLife(Product *product):AddEffect(product)
{
}
ProlongLife::~ProlongLife()
{
}
void ProlongLife::effect()
{
AddEffect::effect();
addNewEffect();
}
TreatingCancer类
treatingcancer.h
#include "addeffect.h"
class TreatingCancer : public AddEffect
{
private:
void addNewEffect();
public:
TreatingCancer(Product *product);
~TreatingCancer();
void effect();
};
treatingcancer.cpp
#include "treatingcancer.h"
#include <iostream>
using namespace std;
void TreatingCancer::addNewEffect()
{
cout<<"防癌治癌 ";
}
TreatingCancer::TreatingCancer(Product *product):AddEffect(product)
{
}
TreatingCancer::~TreatingCancer()
{
}
void TreatingCancer::effect()
{
AddEffect::effect();
addNewEffect();
}
TreatingtHypertension类
treatingthypertension.h
#include "addeffect.h"
class TreatingtHypertension : public AddEffect
{
private:
void addNewEffect();
public:
TreatingtHypertension(Product *product);
~TreatingtHypertension();
void effect();
};
treatingthypertension.cpp
#include "treatingthypertension.h"
#include <iostream>
using namespace std;
void TreatingtHypertension::addNewEffect()
{
cout<<"预防和治疗高血压 ";
}
TreatingtHypertension::TreatingtHypertension(Product *product):AddEffect(product)
{
}
TreatingtHypertension::~TreatingtHypertension()
{
}
void TreatingtHypertension::effect()
{
AddEffect::effect();
addNewEffect();
}
Factory类
factory.h
#include "product.h"
#include "daliwan.h"
#include "cilibei.h"
#include "addeffect.h"
#include "prolonglife.h"
#include "treatingcancer.h"
#include "treatingthypertension.h"
class Factory
{
public:
Factory();
static Product *creatProduct(string product, string brand);
static AddEffect *printDescription(string effect, Product* product);
};
factory.cpp
#include "factory.h"
Factory::Factory()
{
}
Product *Factory::creatProduct(string product, string brand)
{
if(product == "DaLiWan")
{
return new DaLiWan(brand);
}
else if(product == "CiLiBei")
{
return new CiLiBei(brand);
}
return NULL;
}
AddEffect *Factory::printDescription(string effect, Product* product)
{
if(effect == "ProlongLife")
{
return new ProlongLife(product);
}
else if(effect == "TreatingCancer")
{
return new TreatingCancer(product);
}
else if(effect == "TreatingtHypertension")
{
return new TreatingtHypertension(product);
}
return NULL;
}
Client类
client.h
#include <iostream>
#include "product.h"
#include "addeffect.h"
#include "factory.h"
using namespace std;
class Client
{
private:
Product* m_product;
AddEffect *m_effects[3];
string m_productType;
string m_brand;
string m_orderEffects[3];
int m_effectsNum;
public:
Client();
~Client();
bool chooseProduct();
bool nameProductBrand();
bool orderEffects();
void makeProduct();
void showProduct();
};
string changNumtoEffect(int i);
client.cpp
#include "client.h"
#include <iostream>
using namespace std;
#include "cilibei.h"
#include "daliwan.h"
#include "prolonglife.h"
#include "treatingcancer.h"
#include "treatingthypertension.h"
Client::Client()
{
}
Client::~Client()
{
for(int i = m_effectsNum -1; i >= 0; i--)
{
if(m_effects[i] != NULL) delete m_effects[i];
}
if(m_product != NULL) delete m_product;
}
bool Client::chooseProduct()
{
int num;
cout<<"Please choose m_product type:\n";
cout<<"1 大力丸\n"
<<"2 磁力杯\n"
<<"Input a number:";
cin>>num;
cin.ignore();
switch (num) {
case 1:
m_productType = "DaLiWan";
break;
case 2:
m_productType = "CiLiBei";
break;
default:
return false;
}
return true;
}
bool Client::nameProductBrand()
{
string brand;
cout<<"Please name product brand:";
getline(cin, brand);
m_brand = brand;
if(m_brand != "")
return true;
return false;
}
string changNumtoEffect(int i)
{
switch (i) {
case 1:
return "ProlongLife";
case 2:
return "TreatingCancer";
case 3:
return "TreatingtHypertension";
default:
return "";
}
}
bool Client::orderEffects()
{
int num, i = 0;
string str;
cout<<"Please order product's effects:\n";
cout<<"1 延年益寿\n"
<<"2 防癌治癌\n"
<<"3 预防和治疗高血压\n";
cout<<"Please input numbers:";
int size = sizeof(m_orderEffects)/sizeof(string);
while(cin>>num && i <= size)
{
if(i == size) break;
str = changNumtoEffect(num);
if(str != "")
{
m_orderEffects[i++] = str;
}
if(cin.get() == '\n')
break;
}
m_effectsNum = i;
if(m_effectsNum == 0) return false;
return true;
}
void Client::makeProduct()
{
m_product = Factory::creatProduct(m_productType, m_brand);
//添加功能说明
for(int i = 0; i < m_effectsNum; i++)
{
if(i == 0)
{
m_effects[i] = Factory::printDescription(m_orderEffects[i], m_product);
}
else
{
m_effects[i] = Factory::printDescription(m_orderEffects[i], m_effects[i-1]);
}
}
}
void Client::showProduct()
{
if( m_effectsNum > 0)
{
m_effects[m_effectsNum-1]->effect();
}
else
{
m_product->effect();
}
}
main.cpp
#include <iostream>
using namespace std;
#include "client.h"
int main(int argc, char *argv[])
{
Client client;
while(!client.chooseProduct())
{
cout<<"Error!\n";
}
while (!client.nameProductBrand())
{
cout<<"Error!\n";
}
while(!client.orderEffects())
{
cout<<"Error!\n";
}
client.makeProduct();
client.showProduct();
return 0;
}
运行结果

本文介绍装饰模式的概念及其实现,通过实例展示如何动态给对象增加职责,提高代码灵活性。使用C++实现,包括产品类、装饰类及具体装饰类,通过递归调用实现功能叠加。
 装饰模式&spm=1001.2101.3001.5002&articleId=87864330&d=1&t=3&u=3635e3d470cf4e169cd33602155062fa)
1230

被折叠的 条评论
为什么被折叠?



