代理模式
代理模式(Proxy),它是对简单处理程序(或指针)的增强,用于引用一个对象:这个指针被代理(Proxy)对象取代,代理对象位于客户端(Client)和真实执行程序之间,指针有一个可被多个目标利用的钩子。从技术上讲,这种模式在客户端和真实主体(RealSubject)之间插入一个代理对象,维护subject接口和用不同的方式委派它的方法。代理可以透明地做任何事情:懒散创建RealSubject或载入数据,与其它机器交换消息,写时复制策略等。这与HTTP代理有点类似,其客户端(如浏览器)和应用程序依赖于与HTTP服务器的联系,代理在管理连接时可以完成其它任务,如访问控制和缓存大型下载文件。代理模式的对象图与装饰模式对象图在结构上类似,但表达的目的各有不同,装饰者给对象动态增加行为,而代理则控制来自客户端的访问。此外,代理只在需要时才创建RealSubject。
实例[ ]
参与者:
◆客户端(Client):取决于主体(Subject)实现;
◆主体(Subject):RealSubject的抽象;
◆真实主体(RealSubject):完成代价高昂的工作或包含大量的数据;
◆代理(Proxy):为Client提供一个与Subject一致的引用,仅在需要时才创建RealSubject实例或与RealSubject实例通信。
下面是两个被广泛使用的代理模式例子:
1、对象-关系映射(Orms)在运行中创建代理作为实体类的子类,以实现懒散加载(虚拟代理),这个代理会覆盖所有实体方法,在前面追加一个载入程序,在方法被真正调用前不会包含任何数据,Orms代理支持对象间的双向关系,不用加载整个数据库,因为它们被置于当前加载对象图的边界。
2、Java RMI使用远程代理对象(远程代理),当它们的方法被调用时,代理序列化参数,执行网络上的请求,委托调用另一个节点上的真实对象,这种技术允许透明地调用远程对象,不用担心它们是否在同一台机器上,但这种透明度很容易会使执行速度变慢。
下面的代码示例实现了一个ImageProxy,推迟了图像数据的加载。
/** * Subject interface. * Client depends only on this abstraction. */ interface Image { public function getWidth(); public function getHeight(); public function getPath(); /** * @return string the image's byte stream */ public function dump(); } /** * Abstract class to avoid repetition of boilerplate code in the Proxy * and in the Subject. Only the methods which can be provided without * instancing the RealSubject are present here. */ abstract class AbstractImage implements Image { protected $_width; protected $_height; protected $_path; protected $_data; public function getWidth() { return $this->_width; } public function getHeight() { return $this->_height; } public function getPath() { return $this->_path; } } /** * The RealSubject. Always loads the image, even if no dump of the data * is required. */ class RawImage extends AbstractImage { public function __construct($path) { $this->_path = $path; list ($this->_width, $this->_height) = getimagesize($path); $this->_data = file_get_contents($path); } public function dump() { return $this->_data; } } /** * Proxy. Defers loading the image data until it becomes really mandatory. * This class does its best to postpone the very expensive operations * such as the actual loading of the BLOB. */ class ImageProxy extends AbstractImage { public function __construct($path) { $this->_path = $path; list ($this->_width, $this->_height) = getimagesize($path); } /** * Creates a RawImage and exploits its functionalities. */ protected function _lazyLoad() { if ($this->_realImage === null) { $this->_realImage = new RawImage($this->_path); } } public function dump() { $this->_lazyLoad(); return $this->_realImage->dump(); } } /** * Client class that does not use the data dump of the image. * Passing blindly a Proxy to this class and to other Clients makes sense * as the data would be loaded anyway when Image::dump() is called. */ class Client { public function tag(Image $img) { return '; } } $path = '/home/giorgio/shared/Immagini/kiki.png'; $client = new Client(); $image = new RawImage($path); // loading of the BLOB takes place echo $client->tag($image), "\n"; $proxy = new ImageProxy($path); echo $client->tag($proxy), "\n"; // loading does not take place even here
以上代码实现了PHP的代理模式。简单来讲,代理模式就是为其他对象提供一个代理以控制对这个对象的访问。
注意事项[ ]
我们知道了什么是设计模式以及PHP设计模式中的代理模式。这里还有一些关于设计模式的基本概念应该被熟知。
◆算法不能算是一种设计模式,因为算法主要是用来解决计算上的问题,而非设计上的问题。
◆面向对象设计模式通常以类别或物件来描述其中的关系和相互作用,但不涉及用来完成应用程序的特定类别或物件。
◆设计模式主要是使不稳定的依赖于相对稳定、具体依赖于相对抽象,避免会引起麻烦的紧耦合,以增强软件设计面对并适应变化的能力。
◆并非所有的软件模式都是设计模式,设计模式特指软件设计层次上的问题。还有其它非设计模式的模式,如架构模式。