下載地址: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);
}
? ? 從使用演示樣例中就能夠看出,代理類支持客戶使用過程中動態切換數據庫,這是和工廠模式最大的一點不同。特別適用于在常常須要切換類似對象模式的地方。