大话设计模式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\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

大话设计模式C++版——代理模式的相关文章

大话设计模式C++版——工厂模式在COM中的典型应用

上篇<大话设计模式C++版--抽象工厂模式>中,我们拯救世界未遂,留下小小的遗憾,本篇中我们将给出一个解决方案--COM组件技术,同时也顺便扯扯工厂模式在COM组件技术中的应用. 工厂模式违背开放-封闭原则的根本原因在于对象的产生无法通过客户模块外的数据进行控制,如果我们能从xml.注册表.配置文件中写入一个类的名字,然后模块从中读出类名,并根据读出的类名创建对象,那不就和C#高大上的反射技术一样牛B哄哄了.非常幸运,微软的COM组件技术就提供了这么一个平台. 1.COM组件是神马 为了节约篇

【大话设计模式读书笔记——代理模式】

代理模式 代理者是指一个类别可以作为其它东西的接口.代理者可以作任何东西的接口:网络连接.内存中的大对象.文件或其它昂贵或无法复制的资源. 维基百科-代理模式 代理模式实现远程图片加载 /// <summary> /// 图片接口 /// </summary> interface IImage { void Display(); } /// <summary> /// 真实图片类 /// </summary> public class RealImage :

大话设计模式C++版——建造者模式

日常做菜的过程中,经常会有忘记放盐或者放2次盐的经历,最后导致好好的一盘菜让大家无从下口.这个时候就需要用到建造者模式来规范炒菜的过程,来保证每一道菜都会经历加油.放食物.放盐.放味精这4道基本的工序,同时保证每道工序不会重复. 1.炒菜基类 class CCook { public: CCook() {} virtual ~CCook() {} //建造过程函数 //为了保证所有的子类能够按照指定顺序依次实现完整的建造过程,而不会忘记某一个过程的调用(如忘了放盐) void Cook() {

大话设计模式C++版——工厂方法模式

工厂方法模式是以简单工厂模式为基础的,如果未了解简单工厂模式的同学可先浏览<大话设计模式C++版--简单工厂模式>.在简单工厂模式中,提到过简单工厂模式的缺陷,即违背了开发-封闭原则,其主要原因是由于switch的判断结构的使用,使修改或添加新的对象时需要改动简单工厂类的代码,不符合开放-封闭原则,那么工厂方法模式会在那方面有所改进呢?我们仍以简单工厂模式中加减法计算器为例. 1.保持简单工厂模式的 IOperation 接口和实现对象(COperation_Add 和 COperation_

大话设计模式C++版——抽象工厂模式

前面说过,简单工厂模式是最基础的一种设计模式,那以工厂命名的设计模式就是23种设计模式中最多的一种,他们一脉相承,一步一步进化而来,这里就是其中的最后一种--抽象工厂模式(Abstract Factory),其是在工厂方法模式的基础上改进而来,如果没有弄明白工厂方法模式的同学请先观看<大话设计模式C++版--工厂方法模式>. 为什么会有抽象工厂模式?抽象工厂模式是简单工厂模式缺陷的终极解决方式么?NO,抽象工厂模式并不是为了解决简单工厂模式的缺陷而活着,它是因为有新的使命而诞生. 一个简单的例

大话设计模式C++版——简单工厂模式

简单工厂模式应该是所有设计模式中最简单,也最基础的一种模式,以下是一个简单的采用工厂模式写一个加减法的计算器. 1.抽象接口类--依赖倒转原则(高层和底层都要依赖于抽象,针对接口编程) class IOperation { public: IOperation() : m_nNuml(0), m_nNumr(0) {} virtual ~IOperation() {} virtual void SetNum(int nNuml = 0, int nNumr = 0) { m_nNuml = nN

大话设计模式之简单工厂模式&amp;工厂方法模式&amp;抽象工厂模式

创造类模式分为三种:简单工厂模式,工厂模式和抽象工厂模式. 定义: 简单工厂模式:用一个单独的类来做创造实例的过程. 工厂模式:一个用于创建对象的接口,让子类决定实例化哪一个类,讲一个类的实例化 延迟到其子类. 抽象工厂模式:为创建一组相关或相互依赖的对象的类,而不指定具体类. 结构图: 这是简单工厂的结构图,从图中就很好理解. 简单工厂的优点: 根据用户需要,new出需要的对象. 但是简单工厂弊端: 当新加入一个功能是,就要修改工厂.这个时候,就需要工厂模式了. 从图中我们可以看出: 工厂模式

大话设计模式C++版——表驱动法改造简单工厂

上回<大话设计模式C++版--简单工厂模式>中指出了简单工厂模式的缺陷,即违背了开发-封闭原则,其主要原因是由于switch的判断结构的使用,使修改或添加新的对象时需要改动简单工厂类的代码,如何改造switch结构,表驱动法就可以粉墨登场了. 表驱动法的介绍见<数据驱动编程之表驱动法>. 1.面向接口编程,先改造抽象接口类IOperation class IOperation { public: IOperation() : m_nNuml(0), m_nNumr(0) {} vi

大话设计模式_简单工厂模式(Java代码)

简单的描述:一个父类.多个子类,实例化那个子类由一个单独的工厂类来进行 图片摘自大话设计模式: 运算类: 1 package com.longsheng.simpleFactory; 2 3 public class Calculate { 4 5 private double firstNum; 6 private double secondNum; 7 8 public double getFirstNum() { 9 return firstNum; 10 } 11 12 public v