代理模式
代理模式又称 Proxy,代理是一种结构型设计模式,能够提供对象的替代品或其占位符。代理控制着对于原对象的访问,并允许在将请求提交给对象前后进行一些处理。
问题
代理在我们生活中无处不在,比如说:我们超时买的怡宝矿泉水,都零售商从地区代理商那批发来的,我们程序员也经常为了翻过一堵墙用谷歌查找资料使用代理等。
如果有这样一个消耗大量系统资源的巨型对象,我们是偶尔需要使用它,并非总是需要。
我们可以实现延迟初始化——在实际有需要时再创建该对象。对象的所有客户端都要执行延迟初始代码。不好的是,这很可能会带来很多重复代码。
在理想情况下,我们希望将代码直接放入对象的类中,但这并非总是能实现:比如类可能是第三方封闭库的一部分。
解决方法
我们可以新建一个与原服务对象接口相同的代理类,然后更新应用以将代理对象传递给所有原始对象客户端。代理类接收到客户端请求后会创建实际的服务对象,并将所有工作委派给它。
代理将自己伪装成数据库对象,可在客户端或实际数据库对象不知情的情况下处理延迟初始化和缓存查询结果的工作。
这样如果需要在类的主要业务逻辑前后执行一些工作,无需修改类就能完成这项工作。由于代理实现的接口与原类相同,因此可将其传递给任何一个使用实际服务对象的客户端。
结构
DbInterface:数据库接口;定义真实主题和代理的公共方法; Db:实现数据库接口的数据库;隐藏在代理之后; Proxy:实现数据库接口并在内部引用了真实的数据库;
代码示例
数据库接口类
代码语言:javascript复制/**
* 数据库接口
* Interface DbInterface
* @package cxbdashengDesignPatternsProxy
*/
interface DbInterface
{
/**
* 获取数据
* @return mixed
*/
public function get();
/**
* 设置数据
* @return mixed
*/
public function set();
/**
* 删除数据
* @return mixed
*/
public function delete();
}
真实数据库类
代码语言:javascript复制/**
* 真实数据库类
* Class Db
* @package cxbdashengDesignPatternsProxy
*/
class Db implements DbInterface
{
public function get()
{
return '真实数据库获取数据方法';
}
public function set()
{
return '真实数据库设置数据方法';
}
public function delete()
{
return '真实数据库删除数据方法';
}
}
代理类
代码语言:javascript复制/**
* 代理
* Class Proxy
* @package cxbdashengDesignPatternsProxy
*/
class Proxy implements DbInterface
{
private $db = null;
/**
* 构造函数
* Proxy constructor.
*/
public function __construct()
{
if ($this->db == null) {
$this->db = new Db();
}
return $this->db;
}
public function get()
{
// todo 做我代理想做的事
return $this->db->get();
}
public function set()
{
return $this->db->set();
}
public function delete()
{
return $this->db->delete();
}
}
客户端使用
代码语言:javascript复制$db = new Proxy();
// 获取数据
echo $db->get() . PHP_EOL;
// 设置数据
echo $db->set() . PHP_EOL;
//删除数据
echo $db->delete() . PHP_EOL;
输出
代码语言:javascript复制真实数据库获取数据方法
真实数据库设置数据方法
真实数据库删除数据方法
UML
优缺点
优点
- 可以在客户端毫无察觉的情况下控制服务对象。
- 如果客户端对服务对象的生命周期没有特殊要求,可以对生命周期进行管理。
- 即使服务对象还未准备好或不存在,代理也可以正常工作。
- 开闭原则。你可以在不对服务或客户端做出修改的情况下创建新代理。
缺点
- 代码可能会变得复杂,因为需要新建许多类。
- 服务响应可能会延迟。