大话设计模式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);
}
    从使用演示样例中就能够看出,代理类支持客户使用过程中动态切换数据库,这是和工厂模式最大的一点不同。特别适用于在常常须要切换类似对象模式的地方。
原文地址:https://www.cnblogs.com/jhcelue/p/6825574.html