• 大话设计模式C++版——代理模式


        本篇開始前先发个福利,程杰的《大话设计模式》一书高清电子版(带文件夹)已上传至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
    "), 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
    "), stEmployee.tstrName.c_str());
    		return	true;
    	}
    	
    	Employee	GetEmployee(int nID)
    	{
    		Employee	stEmployee;
    		printf("Get an employee from mysql by id %d
    ", nID);
    		return	stEmployee;
    	}
    };
    
    class CEmployeefromAccess : public	IEmployee
    {
    public:
    	bool		InserttoDB(Employee& stEmployee)
    	{
    		_tprintf(_T("Insert employee %s into access
    "), stEmployee.tstrName.c_str());
    		return	true;
    	}
    	
    	Employee	GetEmployee(int nID)
    	{
    		Employee	stEmployee;
    		printf("Get an employee from access by id %d
    ", 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);
    }
        从使用演示样例中就能够看出。代理类支持客户使用过程中动态切换数据库,这是和工厂模式最大的一点不同。特别适用于在常常须要切换类似对象模式的地方。
  • 相关阅读:
    Chrome等浏览器下出现net::ERR_BLOCKED_BY_CLIENT的解决办法
    document.readyState和document.DOMContentLoaded判断DOM的加载完成
    CSS实现进度条
    H5案例分享:移动端滑屏 touch事件
    Passive Event Listeners——让页面滑动更加流畅的新特性
    禁止蒙层底部页面跟随滚动
    跨域Ajax请求时是否带Cookie的设置
    HTML5 元素拖动
    浅谈程序员的英语学习
    (转载)史上最详细的docker学习手册
  • 原文地址:https://www.cnblogs.com/cxchanpin/p/6825581.html
Copyright © 2020-2023  润新知