• 大话设计模式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);
    }

        从使用示例中就可以看出,代理类支持客户使用过程中动态切换数据库,这是和工厂模式最大的一点不同,特别适用于在经常需要切换类似对象模式的地方。

    本文为博主原创文章,如需转载请说明转至http://www.cnblogs.com/organic/
  • 相关阅读:
    VS2015, .NET 4.6, C# 6.0, F# 4.0等重量级产品正式上线
    Visual Studio 2015正式发布
    持续集成并不能消除 Bug,而是让它们非常容易发现和改正(转)
    如何用Excel直接查询Oracle中的数据(转)
    HTTP必知必会(转)
    二叉树的友好实现(转)
    TortoiseGit push失败原因小结(转)
    Android
    对JAVA Bean使用PropertyDescriptor反射调用JAVA方法
    关于MSHTML
  • 原文地址:https://www.cnblogs.com/organic/p/5005641.html
Copyright © 2020-2023  润新知