本篇开始前先发个福利,程杰的《大话设计模式》一书高清电子版(带目录)已上传至CSDN,免积分下载。
下载地址: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 #endif
4、测试示例
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); }
从使用示例中就可以看出,代理类支持客户使用过程中动态切换数据库,这是和工厂模式最大的一点不同,特别适用于在经常需要切换类似对象模式的地方。
版权声明:本文为博主原创文章,如需转载请说明转至http://blog.csdn.net/gufeng99
时间: 2024-10-10 05:07:48