PHP设计模式之代理模式的深入解析
代理模式(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的代理模式。简单来讲,代理模式就是为其他对象提供一个代理以控制对这个对象的访问。