大话设计模式C++版——代理模式
本篇開始前先发个福利。程杰的《大话设计模式》一书高清电子版(带文件夹)已上传至CSDN,免积分下载。
3、被代理对象类
这个样例非常形象,但却非常难看出代理模式的应用和长处。实际上在《大话设计模式C++版——抽象工厂模式》中有一个操作数据库管理员工信息的样例。因为可能会在使用数据库的过程中切换数据库。如曾经用的MySql,可能某个客户要求支持Access,这时就得进行切换了,此时用代理模式一样能够实现。
5.1 代理模式实现员工数据库管理类对数据库的切换
下载地址:http://download.csdn.net/detail/gufeng99/8843487
代理模式是一种比較简单但却有用的设计模式,他能够灵活的更换代理的对象,但保证功能的完整性。就如卖衣服的代理商,他能够代理美特斯邦威的衣服,假设美特斯邦威的衣服被大家吐槽不好卖了。他还能够换去代理卖佐丹奴的。但无论怎么更换,还是能满足大家的需求——买衣服。
以下以大话设计模式书中的样例为例,设计一个代理帮小明送花给小红。
1、根据接口编程。设计代理对象的接口
class IPursuit { public: virtual ~IPursuit() {} virtual void SendFlowers() = 0; };2、代理类。也继承代理对象类,保持接口一致
class CProxy : public IPursuit { public: CProxy() : m_poIPursuit(NULL) {} ~CProxy() { if (m_poIPursuit) { delete m_poIPursuit; m_poIPursuit = NULL; } } void SetPursuit(IPursuit* poIPursuit) { //假设有旧的代理。要先删除,否则会造成内存泄漏 if (m_poIPursuit) { delete m_poIPursuit; } m_poIPursuit = poIPursuit; } void SendFlowers() { if (m_poIPursuit) { printf("Proxy help "); m_poIPursuit->SendFlowers(); } } private: IPursuit* m_poIPursuit; };代理类实际上啥也没干,仅仅是对相同的函数调用了一手被代理的对象的相应函数,当了一回二传手的角色。这里要注意代理对象因为会在代理中被释放。所以代理的对象一律必须是new出来的,即需在堆上创建的。
3、被代理对象类
class CPursuit : public IPursuit { public: CPursuit(TString tstrName) : m_tstrName(tstrName) {} ~CPursuit() {} void SendFlowers() { _tprintf(_T("%s sent flowers to Xiaohong\n"), m_tstrName.c_str()); } private: TString m_tstrName; };另附上TString宏
#ifdef UNICODE #define TString std::wstring #else #define TString std::string #endif4、測试演示样例
void Test() { IPursuit* poIXiaoMing = new CPursuit(_T("XiaoMing")); CProxy oCProxy; oCProxy.SetPursuit(poIXiaoMing); oCProxy.SendFlowers(); }5、代理类的应用
这个样例非常形象,但却非常难看出代理模式的应用和长处。实际上在《大话设计模式C++版——抽象工厂模式》中有一个操作数据库管理员工信息的样例。因为可能会在使用数据库的过程中切换数据库。如曾经用的MySql,可能某个客户要求支持Access,这时就得进行切换了,此时用代理模式一样能够实现。
5.1 代理模式实现员工数据库管理类对数据库的切换
typedef struct Employee { int nID; TString tstrName; }; class IEmployee { public: ~IEmployee() {} virtual bool InserttoDB(Employee& stEmployee) = 0; virtual Employee GetEmployee(int nID) = 0; }; class CProxy : public IEmployee { public: public: CProxy() : m_poIEmployee(NULL) {} ~CProxy() { if (m_poIEmployee) { delete m_poIEmployee; m_poIEmployee = NULL; } } void SetEmployee(IEmployee* poIEmployee) { if (m_poIEmployee) { delete m_poIEmployee; } m_poIEmployee = poIEmployee; } bool InserttoDB(Employee& stEmployee) { if (m_poIEmployee) { return m_poIEmployee->InserttoDB(stEmployee); } return false; } Employee GetEmployee(int nID) { if (m_poIEmployee) { return m_poIEmployee->GetEmployee(nID); } Employee stEmployee; return stEmployee; } private: IEmployee* m_poIEmployee; }; class CEmployeefromMysql : public IEmployee { public: bool InserttoDB(Employee& stEmployee) { _tprintf(_T("Insert employee %s into mysql\n"), stEmployee.tstrName.c_str()); return true; } Employee GetEmployee(int nID) { Employee stEmployee; printf("Get an employee from mysql by id %d\n", nID); return stEmployee; } }; class CEmployeefromAccess : public IEmployee { public: bool InserttoDB(Employee& stEmployee) { _tprintf(_T("Insert employee %s into access\n"), stEmployee.tstrName.c_str()); return true; } Employee GetEmployee(int nID) { Employee stEmployee; printf("Get an employee from access by id %d\n", nID); return stEmployee; } };5.2 使用演示样例
void DataBaseTest() { IEmployee* poIEmployee = new CEmployeefromMysql(); CProxy oCProxy; oCProxy.SetEmployee(poIEmployee); Employee stEmployee; stEmployee.nID = 1; stEmployee.tstrName = _T("Jim"); oCProxy.InserttoDB(stEmployee); //切换数据库对象 poIEmployee = new CEmployeefromAccess(); oCProxy.SetEmployee(poIEmployee); oCProxy.InserttoDB(stEmployee); }从使用演示样例中就能够看出,代理类支持客户使用过程中动态切换数据库。这是和工厂模式最大的一点不同。特别适用于在常常须要切换类似对象模式的地方。