[toc]
## 举个例子
**代收快递**
* 周四下单, 周末双休, 你以为周末快递能到, 所以选了家里的地址
* 结果周五快递就到了, 但是你在上班
* 你让宅在家里的邻居帮你代收
## 代码示例
```php
<?php
// 接收包裹
class ReceiveParcel {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
public function receive($parcelContent) {
}
}
// Tony接收
class TonyReception extends ReceiveParcel {
private $phoneNum;
public function __construct($name, $phoneNum) {
parent::__construct($name);
$this->phoneNum = $phoneNum;
}
public function getPhoneNum() {
return $this->phoneNum;
}
public function receive($parcelContent) {
echo "货物主人:{$this->getName()}, 手机号:{$this->getPhoneNum()} ";
echo "收到一个包裹, 包裹内容: {$parcelContent}" . PHP_EOL;
}
}
// Wendy接收
class WendyReception extends ReceiveParcel {
private $receiver;
public function __construct($name, $receiver) {
parent::__construct($name);
$this->receiver = $receiver;
}
public function receive($parcelContent) {
echo "我是" . $this->receiver->getName() . "的朋友, 我来帮他代收快递!" . PHP_EOL;
if ($this->receiver) {
$this->receiver->receive($parcelContent);
}
echo "代收人:" . $this->getName();
}
}
$tony = new TonyReception("Tony", "18512345678");
$wendy = new WendyReception("Wendy", $tony);
$wendy->receive("雪地靴");
```
```
D:\soft\php72\php.exe D:\project\php_dp\index.php
我是Tony的朋友, 我来帮他代收快递!
货物主人:Tony, 手机号:18512345678 收到一个包裹, 包裹内容: 雪地靴
代收人:Wendy
Process finished with exit code 0
```
## 代码说明
> 包裹实际上是 Tony 的,但是 Wendy 代替 Tony 的身份帮忙接收了包裹,Wendy 需要使用 Tony 的身份并获得快递员的验证(Tony 手机号)才能成功接收包裹。
## 什么是代理模式?
1. 给某一个对象提供一个代理,并由代理对象控制对原对象的引用。
1. 一个客户不想或者不能直接引用一个对象,此时可以通过一个称之为“代理”的第三者来实现间接引用。
1. 如上面的示例中,Tony 因为不在家,所以不能亲自接收包裹,但他可以叫 Wendy 来代他接收,这里 Wendy 就是代理,她代理了 Tony 的身份去接收快递。
![](https://box.kancloud.cn/c787295bebfd570071d155b6edbbf1ed_509x321.png)
## 设计要点
1. **主题(Subject)**:定义“操作/活动/任务”的接口类。
1. **真实主题(RealSubject)**:真正完成“操作/活动/任务”的具体类。
1. **代理主题(ProxySubject)**:代替真实主题完成“操作/活动/任务”的代理类
## 优缺点
**代理模式的优点**
1. 代理模式能够协调调用者和被调用者,在一定程度上降低了系统的耦合度。
1. 可以灵活地隐藏被代理对象的部分功能和服务,也增加额外的功能和服务。
**代理模式的缺点**
1. 由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。
1. 实现代理模式需要额外的工作,有些代理模式的实现非常复杂。
## 应用场景
1. 不想或者不能直接引用一个对象时
如在移动端加载网页信息时,因为下载真实大图比较耗费流量和性能,可以用一个小图代替进行渲染(用一个代理对象去下载小图),在真正点击图片时,才去下载大图,显示大图效果。还有 HTML 中的占位符,其实也是代理的思想。
1. 想对一个对象的功能进行加强时
如在字体(Font)渲染时,对粗体(BoldFont)进行渲染时,可使用字体 Font 对象进行代理,只要在对 Font 进行渲染后,进行一步加粗的操作即可。