【设计模式】为别人做嫁衣 --- 代理模式
一,概述
定义:代理模式(Proxy)为另一个对象提供一个替身或占位符以控制对这个对象的访问,简而言之就是用一个对象来代表另一个对象。
作用:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。思想:为了提供额外的处理或者不同的操作而在实际对象与调用者之间插入一个代理对象。这些额外的操作通常需要与实际对象进行通信。
远程(Remote)代理:为一个位于不同的地址空间的对象提供一个局域代表对象。这个不同的地址空间可以是在本机器中,也可是在另一台机器中。远程代理又叫做大使(Ambassador)。好处是系统可以将网络的细节隐藏起来,使得客户端不必考虑网络的存在。客户完全可以认为被代理的对象是局域的而不是远程的,而代理对象承担了大部份的网络通讯工作。由于客户可能没有意识到会启动一个耗费时间的远程调用,因此客户没有必要的思想准备。
虚拟(Virtual)代理(图片延迟加载的例子):根据需要创建一个资源消耗较大的对象,使得此对象只在需要时才会被真正创建。使用虚拟代理模式的好处就是代理对象可以在必要的时候才将被代理的对象加载;代理可以对加载的过程加以必要的优化。当一个模块的加载十分耗费资源的情况下,虚拟代理的好处就非常明显。
Copy-on-Write代理:虚拟代理的一种。把复制(克隆)拖延到只有在客户端需要时,才真正采取行动。
智能引用(Smart Reference)代理:当一个对象被引用时,提供一些额外的操作,比如将对此对象调用的次数记录下来等。
二,示例
描述:卓贾易让戴励送给李娇娇礼物,追求李娇娇。
1)小菜第一版代码
缺点:卓贾易直接行使送礼物类,不符合题目意思。
#include <iostream> class SchoolGirl //要追的女孩 { public: void SetName(std::string str)//名字 { m_Name = str; }; std::string GetName(void) //获取女孩名字 { return m_Name; }; private: std::string m_Name; }; class Pursuit//追求行为类 { public: Pursuit(SchoolGirl* mm) { m_mm = mm; }; void GiveDolls() { std::cout << m_mm->GetName() << "送你洋娃娃" << std::endl; }; void GiveFlower() { std::cout << m_mm->GetName() << "送你鲜花" << std::endl; }; void GiveChocolate() { std::cout << m_mm->GetName() << "送你巧克力" << std::endl; }; private: SchoolGirl* m_mm; }; int main() { SchoolGirl* jiaojiao = new SchoolGirl();//初始化要追求的对象 jiaojiao->SetName("李娇娇"); //事实上娇娇并不认识卓贾易 Pursuit* zhuojiayi = new Pursuit(jiaojiao); zhuojiayi->GiveChocolate(); zhuojiayi->GiveDolls(); zhuojiayi->GiveFlower(); delete jiaojiao; delete zhuojiayi; return 0; }
2)小菜代理第二版
缺点:也不是让戴励自己亲自追求,不符合题意。
#include <iostream> class SchoolGirl //要追的女孩 { public: void SetName(std::string str)//名字 { m_Name = str; }; std::string GetName(void) //获取女孩名字 { return m_Name; }; private: std::string m_Name; }; class Proxy//代理类,其实是戴励 { public: Proxy(SchoolGirl* mm) { m_mm = mm; }; void GiveDolls() { std::cout << m_mm->GetName() << "送你洋娃娃" << std::endl; }; void GiveFlower() { std::cout << m_mm->GetName() << "送你鲜花" << std::endl; }; void GiveChocolate() { std::cout << m_mm->GetName() << "送你巧克力" << std::endl; }; private: SchoolGirl* m_mm; }; int main() { SchoolGirl* jiaojiao = new SchoolGirl(); jiaojiao->SetName("李娇娇"); Proxy* daili = new Proxy(jiaojiao); daili->GiveChocolate(); daili->GiveDolls(); daili->GiveFlower(); return 0; }
3)小菜第三版
改进:添加接口,让一个对象实现接口,代理负责运用接口。
实现:代理同样实现接口,只是代理实现接口的时候实际上是调用实际实现者的方法。
#include <iostream> class SchoolGirl //要追的女孩 { public: void SetName(std::string str)//名字 { m_Name = str; }; std::string GetName(void) //获取女孩名字 { return m_Name; }; private: std::string m_Name; }; class GiveGift //送礼物接口(抽象函数就是接口) { virtual void GiveDolls(void) = 0; virtual void GiveFlower(void) = 0; virtual void GiveChocolate(void) = 0; }; class Pursuit :public GiveGift//追求者去实现礼物接口 { public: Pursuit(SchoolGirl* mm) { m_mm = mm; }; void GiveDolls() { std::cout << m_mm->GetName() << "送你洋娃娃" << std::endl; }; void GiveFlower() { std::cout << m_mm->GetName() << "送你鲜花" << std::endl; }; void GiveChocolate() { std::cout << m_mm->GetName() << "送你巧克力" << std::endl; }; private: SchoolGirl* m_mm; }; class Proxy :public GiveGift//代理类(也去实现送礼物接口,实际上是调用追求者的方法) { public: Proxy(SchoolGirl* mm) { m_gg = new Pursuit(mm); }; ~Proxy() { if (m_gg != NULL) { delete m_gg; m_gg = NULL; } }; void GiveDolls() { m_gg->GiveDolls(); }; void GiveFlower() { m_gg->GiveFlower(); }; void GiveChocolate() { m_gg->GiveChocolate(); }; private: Pursuit* m_gg; }; int main() { SchoolGirl* jiaojiao = new SchoolGirl(); jiaojiao->SetName("李娇娇"); Proxy* daili = new Proxy(jiaojiao); daili->GiveChocolate(); daili->GiveDolls(); daili->GiveFlower(); return 0; }
三,代理模式的经典模板
class Subject { public: virtual void Request(void) = 0; }; class RealSubject : public Subject { public: void Request(void) { std::cout << "真实的请求" << std::endl; }; }; class Proxy : public Subject { public: Proxy() :m_realSubject(NULL) { } void Request(void) { if (m_realSubject == NULL) { m_realSubject = new RealSubject(); } m_realSubject->Request(); }; private: RealSubject* m_realSubject; }; int main() { Proxy* daili = new Proxy(); daili->Request(); delete daili; return 0; }