代码改变世界

设计模式初学者系列之代理模式

2008-02-18 15:48  横刀天笑  阅读(3397)  评论(2编辑  收藏  举报

看到代理(Proxy),首先映入大脑中的肯定是网络上为数众多的代理服务器。我们的客户机由于各种原因,不能直接连接到真正的服务器、直接访问速度慢,有的应用中甚至在代理服务器上作权限的访问控制。大部分代理服务器都有一个缓存功能,当客户机访问某内容的时候,代理服务器首先查找本地缓存里是否有这个内容,如果有则直接将其返回,否则代理服务器将向真正的服务器发送请求,将真正的服务器的响应内容发送给客户端而且将这个内容也在本地缓存中保留一份,以备后用。

其实今天我们要谈的代理模式也是和这个类似。

在Gof-DP中,代理模式是对象结构型模式,他们是这样定义代理模式的:为其他对象提供一个代理或占位符,以控制对这个兑现的访问。

其实,是否使用代理客户端并不知晓,即使我们使用了代理服务器我们还是同样的在浏览器输入同样的网址,要做到客户端不知道里面的黑幕,只有拿出我们的杀手锏:“面向接口编程”。我们的代理服务器和真实的服务器提供同样的接口。

clip_image003

代理服务器和真实服务器的接口

public interface IServer

{

string Request(string ip,string port,string fileName);

}

缓存代理服务器

public class CacheProxy : IServer

{

private Hashtable cache = new Hashtable();

//在这个方法里我们实现缓存逻辑

public string Request(string ip, string port,string fileName)

{

string content;

if (cache[string.Format("{0}-{1}-{2}", ip, port, fileName)] == null)

content = new RealServer(ip, port).Request(ip, port, fileName);

cache[string.Format("{0}-{1}-{2}", ip, port, fileName)] = content;

return content;

}

}

真实的服务器

public class RealServer : IServer

{

public RealServer(string ip, string port)

{

}

public string Request(string ip, string port, string fileName)

{

return string.Format("This is the file's content,file's name is {0}",fileName);

}

}

(课后作业:自己实现AccessControlProxy)

在实际应用中,代理模式也有很多应用场景。

在Gof-DP中举了这样一个例子,一个文档编辑器中需要插入图像,图像是比起文本更占自愿的对象,但是并不是一打开文档的时候,所有的图像都会Draw出来的,只有等到它显示的时候(比如拖动滚动条,图片显示了),在这种情况下文档编辑器可以不实际和图像对象交互,而是和一个图像代理交互,等到调用图像代理的Draw方法的时候才去调用真正图像的Draw方法,调用后图像代理还可以将图像本地缓存起来,再次需要的时候不需要从硬盘上重新读取。

很多代理服务器其实起的是一个缓存的作用,受这个启示,我们在做数据访问层的时候也可以使用代理模式:数据库操作是一个非常消耗资源的操作,我们可以做一个数据访问代理,业务层并不和实际的数据操作交互,而是和这个缓存代理交互。

clip_image004

我们在这个CacheDataProvider缓存数据,只有CacheDataProvider中没有数据或数据失效的时候才请求RealDataProvider,并且同时在自己的本地缓存中保留一份,在这个CacheDataProvider中我们还可以实现缓存的同步更新策略,SQL语句合法性验证等问题。

在Gof-DP关于Proxy模式的适用性里面谈到几种典型应用:

一、远程代理 比如在WCF中,客户端要访问Service,先是请求本地的Proxy,这个Proxy再通过Channel访问远程的Service,不管本地的Proxy和远程的Service,他们都实现同一个契约(Contract)。

二、虚拟代理 在创建昂贵资源的时候使用,比如上面Gof提到的图像代理。

三、保护代理 这个是对原始对象的访问做访问控制的,比如权限验证等啊。

四、智能引用 它代替原本的指针(*,->),然后在这个上面添加更多的功能(所以变的智能了)。智能引用有很多典型应用:

第一个、C++里面的智能指针,这在C++里可是一个大课题,智能指针记录了到真实对象引用的次数,当没有引用到真实对象的时候,我们就可以自动的销毁了。

第二个、当第一次引用的时候将持久化对象加载到内存中

第三个、在访问真实对象之前锁定它,保证不会有其它对象修改它。

通过设计模式的学习,我们发现在大多数模式中,都是通过添加中间层来隔离变化,将客户代码和易变化代码中间的藕和性降低,降低后我们就可以在这个“隔板”后面做更多的“黑箱”操作了,而客户对此却一无所知。我们也可以在这个中间层上做手脚,将一些职责转移(比如今天的代理模式)。