c++设计模式-装饰器模式和代理模式
namespace _nmsp1 { //抽象的控件类 class Control { public: virtual void draw() = 0; //draw方法,用于将自身绘制到屏幕上。 public: virtual ~Control() {} //做父类时析构函数应该为虚函数 }; //列表控件类 class ListCtrl :public Control { public: virtual void draw() { cout << "绘制普通的列表控件!" << endl; //具体可以用DirectX或OpenGL来绘制 } }; //抽象的装饰器类 class Decorator :public Control { public: Decorator(Control* tmpctrl) :m_control(tmpctrl) {} //构造函数 virtual void draw() { m_control->draw(); //虚函数,调用的是哪个draw,取决于m_control指向的对象 } private: Control* m_control; //需要被装饰的其他控件,这里用的是Control *; }; //---------------------- //具体的“边框”装饰器类 class BorderDec :public Decorator { public: BorderDec(Control* tmpctrl) :Decorator(tmpctrl) {} //构造函数 virtual void draw() { Decorator::draw(); //调用父类的draw方法以保持以往已经绘制出的内容 drawBorder(); //也要绘制自己的内容 } private: void drawBorder() { cout << "绘制边框!" << endl; } }; //具体的“垂直滚动条”装饰器类 class VerScrollBarDec :public Decorator { public: VerScrollBarDec(Control* tmpctrl) :Decorator(tmpctrl) {} //构造函数 virtual void draw() { Decorator::draw(); //调用父类的draw方法以保持以往已经绘制出的内容 drawVerScrollBar(); //也要绘制自己的内容 } private: void drawVerScrollBar() { cout << "绘制垂直滚动条!" << endl; } }; //具体的“水平滚动条”装饰器类 class HorScrollBarDec :public Decorator { public: HorScrollBarDec(Control* tmpctrl) :Decorator(tmpctrl) {} //构造函数 virtual void draw() { Decorator::draw(); //调用父类的draw方法以保持以往已经绘制出的内容 drawHorScrollBar(); //也要绘制自己的内容 } private: void drawHorScrollBar() { cout << "绘制水平滚动条!" << endl; } }; } int main() { //(1)创建一个又带边框,又带垂直滚动条的列表控件 //首先绘制普通的列表控件 _nmsp1::Control* plistctrl = new _nmsp1::ListCtrl(); //本体 //接着“借助普通的列表控件”,可以通过边框装饰器绘制出一个“带边框的列表控件” _nmsp1::Decorator* plistctrl_b = new _nmsp1::BorderDec(plistctrl); //_nmsp1::Decorator*用成_nmsp1::Control * //接着“借助带边框的列表控件”,就可以通过垂直滚动条装饰器绘制出一个“带垂直滚动条又带边框的列表控件” _nmsp1::Decorator* plistctrl_b_v = new _nmsp1::VerScrollBarDec(plistctrl_b); plistctrl_b_v->draw(); //这里完成最终绘制 cout << "--------------------" << endl; //(2)创建一个只带水平滚动条的列表控件 //首先绘制普通的列表控件 _nmsp1::Control* plistctrl2 = new _nmsp1::ListCtrl(); //本体 //接着“借助普通的列表控件”,可以通过水平滚动条装饰器绘制出一个“带水平滚动条的列表控件” _nmsp1::Decorator* plistctrl2_h = new _nmsp1::HorScrollBarDec(plistctrl2); plistctrl2_h->draw(); //(3)释放资源 delete plistctrl_b_v; delete plistctrl_b; delete plistctrl; delete plistctrl2_h; delete plistctrl2; }
装饰(Decorator)模式:装饰器模式/包装模式,结构型模式
namespace _nmsp2 { //抽象饮料类 class Beverage { public: virtual int getprice() = 0; //获取价格 public: virtual ~Beverage() {} }; //水果饮料类 class FruitBeverage : public Beverage { public: virtual int getprice() { return 10; //一杯单纯的水果饮料,售价为10元 } }; //抽象的装饰器类 class Decorator :public Beverage { public: Decorator(Beverage* tmpbvg) :m_pbvg(tmpbvg) {} //构造函数 virtual int getprice() { return m_pbvg->getprice(); } private: Beverage* m_pbvg; }; //具体的“砂糖”装饰器类 class SugarDec :public Decorator { public: SugarDec(Beverage* tmpbvg) :Decorator(tmpbvg) {} //构造函数 virtual int getprice() { return Decorator::getprice() + 1; //额外加多1元,要调用父类的getprice方法以把以往的价格增加进来 } }; //具体的“牛奶”装饰器类 class MilkDesc :public Decorator { public: MilkDesc(Beverage* tmpbvg) :Decorator(tmpbvg) {} //构造函数 virtual int getprice() { return Decorator::getprice() + 2; //额外加多2元,要调用父类的getprice方法以把以往的价格增加进来 } }; //具体的“珍珠”装饰器类 class BubbleDesc :public Decorator { public: BubbleDesc(Beverage* tmpbvg) :Decorator(tmpbvg) {} //构造函数 virtual int getprice() { return Decorator::getprice() + 2; //额外加多2元,要调用父类的getprice方法以把以往的价格增加进来 } }; } int main() { //创建一杯单纯的水果饮料,价格10元: _nmsp2::Beverage* pfruit = new _nmsp2::FruitBeverage(); //向饮料中增加珍珠,价格多加了2元 _nmsp2::Decorator *pfruit_addbubb = new _nmsp2::BubbleDesc(pfruit); //再向饮料中增加砂糖,价格又加多了1元 _nmsp2::Decorator* pfruit_addbubb_addsugar = new _nmsp2::SugarDec(pfruit_addbubb); //输出最终的价格 cout << "加了珍珠又加了砂糖的水果饮料最终价格是:" << pfruit_addbubb_addsugar->getprice() << "元人民币" << endl; //释放资源 delete pfruit_addbubb_addsugar; delete pfruit_addbubb; delete pfruit; return 0; }
代理模式
namespace _nmsp1 { class WebAddr { public: virtual void visit() = 0; //执行访问网站的动作,子类中会重新实现 virtual ~WebAddr() {} //做父类时析构函数应该为虚函数 }; //某购物网站 class WebAddr_Shopping :public WebAddr { public: virtual void visit() { //......访问该购物网站,可能涉及复杂的网络通信 cout << "访问WebAddr_Shopping购物网站!" << endl; } }; //某视频网站 class WebAddr_Video :public WebAddr { public: virtual void visit() { //......访问该视频网站,可能涉及复杂的网络通信 cout << "访问WebAddr_Video视频网站!" << endl; } }; //------------------------- //网站代码类 class WebAddrProxy :public WebAddr { public: //构造函数,引入的目的是传递进来要访问的具体网站 WebAddrProxy(WebAddr* pwebaddr) :mp_webaddr(pwebaddr) {} public: virtual void visit() { //在这里进行访问的合法性检查,日志记录或者流量限制...... mp_webaddr->visit(); //在这里可以进行针对返回数据的过滤...... } private: WebAddr* mp_webaddr; //代码要访问的具体网站 }; //----------------- //专门针对某购物网站WebAddr_Shopping的代理 class WebAddr_Shopping_Proxy :public WebAddr { public: virtual void visit() { //在这里进行访问的合法性检查,日志记录或者流量限制...... WebAddr_Shopping* p_webaddr = new WebAddr_Shopping(); p_webaddr->visit(); //在这里可以进行针对返回数据的过滤...... //释放资源 delete p_webaddr; } }; } int main() { _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);//程序退出时检测内存泄漏并显示到“输出”窗口 _nmsp1::WebAddr* wba1 = new _nmsp1::WebAddr_Shopping(); wba1->visit(); //访问该购物网站 _nmsp1::WebAddr* wba2 = new _nmsp1::WebAddr_Video(); wba2->visit(); //访问该视频网站 //资源释放 delete wba1; delete wba2; /* _nmsp1::WebAddr* wba1 = new _nmsp1::WebAddr_Shopping(); _nmsp1::WebAddr* wba2 = new _nmsp1::WebAddr_Video(); _nmsp1::WebAddrProxy* wbaproxy1 = new _nmsp1::WebAddrProxy(wba1); wbaproxy1->visit(); //通过代理去访问WebAddr_Shopping购物网站 _nmsp1::WebAddrProxy* wbaproxy2 = new _nmsp1::WebAddrProxy(wba2); wbaproxy2->visit(); //通过代理去访问WebAddr_Video视频购物网站 //资源释放 delete wba1; delete wba2; //资源释放 delete wbaproxy1; delete wbaproxy2; */ /* _nmsp1::WebAddr_Shopping_Proxy* wbasproxy = new _nmsp1::WebAddr_Shopping_Proxy(); wbasproxy->visit(); //访问实际的购物网站 //资源释放 delete wbasproxy; */ return 0; }
namespace _nmsp2 { //缓存/缓冲代理(Cache Proxy)范例 vector<string> g_fileItemList; //抽象主题 class ReadInfo { public: virtual void read() = 0; virtual ~ReadInfo() {} }; //真实主题 class ReadInfoFromFile : public ReadInfo { public: virtual void read() //从文件中读信息(读取test.txt的内容) { ifstream fin("test.txt"); if (!fin) { cout << "文件打开失败" << endl; return; } string linebuf; while (getline(fin, linebuf)) //从哪个文件中逐行读入内容 { if (!linebuf.empty()) //读的不是空行 { g_fileItemList.push_back(linebuf); //将文件中的每一行都保存到vector容器中。 //cout << linebuf << endl; } } fin.close(); //关闭文件输入流 } }; //代理主题 class ReadInfoProxy :public ReadInfo { public: virtual void read() { if (!m_loaded) { //没有从文件中载入信息,则载入 m_loaded = true; //标记已经从文件中载入信息了 cout << "从文件中读取了如下数据---------:" << endl; ReadInfoFromFile* rf = new ReadInfoFromFile(); rf->read(); //将文件中的数据读入全局容器g_fileItemList delete rf; //释放资源 } else { cout << "从缓存中读取了如下数据----------:" << endl; } //现在数据一定在g_fileItemList中,开始显示 for (auto iter = g_fileItemList.begin(); iter != g_fileItemList.end(); ++iter) { cout << *iter << endl; } } private: bool m_loaded = false; //false表示还没有从文件中读出数据到内存 }; } int main() { _nmsp2::ReadInfo* preadinfoproxy = new _nmsp2::ReadInfoProxy(); preadinfoproxy->read(); //第一次调用read是借助代理使用真实主题到文件中拿数据 preadinfoproxy->read(); //后续调用read都是直接从缓存中拿数据 preadinfoproxy->read(); //从缓存中拿数据 //资源释放 delete preadinfoproxy; system("pause"); return 0; }
装饰器模式和代理模式在设计模式中有不同的应用场景和作用。
装饰器模式(Decorator Pattern)主要用于动态地给对象添加额外的职责。它允许向一个现有的对象添加新的功能,而无需改变其结构。装饰器模式通过创建一个装饰器类,该类实现了与被装饰对象相同的接口,并在内部持有一个被装饰对象的实例,从而可以动态地添加新的功能。这样就可以在运行时动态地添加、移除或者组合对象的行为,而不影响其原始行为。
代理模式(Proxy Pattern)则是用一个代理对象来控制对原始对象的访问。代理模式可以用于控制对对象的访问,以实现对原始对象的操作的增强、延迟加载或者权限控制。代理模式常见的应用包括远程代理、虚拟代理、保护代理等。代理对象通常会持有对真实对象的引用,并在对真实对象的访问上进行控制,例如在对真实对象的请求前后执行额外的逻辑。
因此,装饰器模式主要用于动态地扩展对象的功能,而代理模式主要用于控制对对象的访问。两种模式在应用场景和解决问题上有一定的差异,但都能够提供灵活性和可维护性。
当使用C++实现装饰器模式时,我们可以考虑一个简单的示例:假设我们有一个Shape
接口和其具体实现类Circle
,现在我们希望能够动态地给Circle
添加额外的功能,比如颜色或者边框。这时候就可以使用装饰器模式。
首先,我们定义Shape
接口及其具体实现类Circle
:
// Shape接口
class Shape {
public:
virtual void draw() = 0;
};
// 具体的形状类:圆形
class Circle : public Shape {
public:
void draw() override {
std::cout << "画一个圆形" << std::endl;
}
};
然后,我们创建一个装饰器类ShapeDecorator
,用于动态地添加额外的功能。这里以添加颜色为例:
// 装饰器类
class ShapeDecorator : public Shape {
protected:
Shape* decoratedShape;
public:
ShapeDecorator(Shape* shape) : decoratedShape(shape) {}
void draw() override {
decoratedShape->draw();
}
};
// 具体的装饰器类:添加颜色
class ColorDecorator : public ShapeDecorator {
private:
std::string color;
public:
ColorDecorator(Shape* shape, const std::string& col) : ShapeDecorator(shape), color(col) {}
void draw() override {
decoratedShape->draw();
std::cout << "颜色: " << color << std::endl;
}
};
使用装饰器模式,我们可以这样来使用:
int main() {
// 创建一个原始的圆形对象
Shape* circle = new Circle();
// 使用装饰器来动态地添加颜色
Shape* redCircle = new ColorDecorator(circle, "红色");
redCircle->draw();
delete circle;
delete redCircle;
return 0;
}
在这个示例中,我们通过装饰器模式动态地给Circle
对象添加了颜色的功能,而不需要修改Circle
类的结构。
当使用C++实现装饰器模式时,我们可以考虑一个简单的示例:假设我们有一个Shape
接口和其具体实现类Circle
,现在我们希望能够动态地给Circle
添加额外的功能,比如颜色或者边框。这时候就可以使用装饰器模式。
首先,我们定义Shape
接口及其具体实现类Circle
:
// Shape接口
class Shape {
public:
virtual void draw() = 0;
};
// 具体的形状类:圆形
class Circle : public Shape {
public:
void draw() override {
std::cout << "画一个圆形" << std::endl;
}
};
然后,我们创建一个装饰器类ShapeDecorator
,用于动态地添加额外的功能。这里以添加颜色为例:
// 装饰器类
class ShapeDecorator : public Shape {
protected:
Shape* decoratedShape;
public:
ShapeDecorator(Shape* shape) : decoratedShape(shape) {}
void draw() override {
decoratedShape->draw();
}
};
// 具体的装饰器类:添加颜色
class ColorDecorator : public ShapeDecorator {
private:
std::string color;
public:
ColorDecorator(Shape* shape, const std::string& col) : ShapeDecorator(shape), color(col) {}
void draw() override {
// 调用被装饰对象的draw方法
decoratedShape->draw();
// 添加额外的功能:颜色
std::cout << "颜色: " << color << std::endl;
}
};
使用装饰器模式,我们可以这样来使用:
int main() {
// 创建一个原始的圆形对象
Shape* circle = new Circle();
// 使用装饰器来动态地添加颜色
Shape* redCircle = new ColorDecorator(circle, "红色");
redCircle->draw();
delete circle;
delete redCircle;
return 0;
}
在这个示例中,我们通过装饰器模式动态地给Circle
对象添加了颜色的功能,而不需要修改Circle
类的结构。这样做的好处在于,可以在运行时动态地添加新的功能,而且还能保持类的单一职责原则,使得代码更加灵活和可维护。
当使用C++实现代理模式时,我们可以考虑一个简单的示例:假设我们有一个接口Image
和其具体实现类RealImage
,现在我们希望能够通过代理来控制对RealImage
对象的访问。这时候就可以使用代理模式。
首先,我们定义Image
接口及其具体实现类RealImage
:
// Image接口
class Image {
public:
virtual void display() = 0;
};
// 具体的图像类:实际图像
class RealImage : public Image {
private:
std::string filename;
public:
RealImage(const std::string& file) : filename(file) {}
void display() override {
std::cout << "显示图像: " << filename << std::endl;
}
};
然后,我们创建一个代理类ProxyImage
,用于控制对RealImage
对象的访问:
// 代理类
class ProxyImage : public Image {
private:
std::string filename;
RealImage* realImage;
void loadImage() {
if (realImage == nullptr) {
realImage = new RealImage(filename);
}
}
public:
ProxyImage(const std::string& file) : filename(file), realImage(nullptr) {}
void display() override {
loadImage();
realImage->display();
}
};
使用代理模式,我们可以这样来使用:
int main() {
// 使用代理来控制对RealImage对象的访问
Image* image = new ProxyImage("test.jpg");
// 第一次访问,会加载真实图像
image->display();
// 第二次访问,不需要重新加载真实图像
image->display();
delete image;
return 0;
}
在这个示例中,我们通过代理模式控制了对RealImage
对象的访问。代理类ProxyImage
负责在必要时创建并管理RealImage
对象,并在适当的时机调用RealImage
对象的方法。通过代理模式,我们可以实现延迟加载、访问控制等功能,而不需要直接访问RealImage
对象。