我和王争学设计模式|代理模式
目录
- 定义
- 使用场景
- 需求描述
- 方法一(接口式)
- 方法二(继承式)
- 方法三 (动态代理)
- 其他参考
极客时间《设计模式》(王争)
定义
为其他对象提供一种代理以控制对这个对象的访问
使用场景
在不改变原始类(或叫被代理类)代码的情况下,通过引入代理类来给原始类附加功能。比如:监控、统计、鉴权、限流、事务、幂等、日志。将这些附加功能与业务功能解耦,放到代理类统一处理,让程序员只需要关注业务方面的开发。除此之外,代理模式还可以用在 RPC、缓存等应用场景中。
需求描述
性能计数器,用来收集类中函数的执行时间。
方法一(接口式)
使用接口实现方式的前置条件,就是对代码有百分之百控制控制权,从原始类中抽离出要实现的接口,再使得代理类实现抽离出来的接口,从而实现非功能性扩展的需求。
GitHub Gitee
定义接口
<?phpnamespace App;interface IUserController
{public function login($telephone, $password);public function register($telephone, $password);
}
原始类实现接口
<?php
namespace App;/*** 原始类* Class UserController* @package App*/
class UserController implements IUserController
{/*** @param $telephone* @param $password* @return array*/public function login($telephone, $password){// 模拟执行时间usleep(100);echo 'login' . PHP_EOL;return [];}/*** @param $telephone* @param $password* @return array*/public function register($telephone, $password){// 模拟执行时间usleep(100);echo 'register' .PHP_EOL;return [];}
}
代理类实现接口
<?php
namespace App;/*** 代理类* Class UserControllerProxy* @package App*/
class UserControllerProxy implements IUserController
{protected $metricsCollector;protected $userController;public function __construct(UserController $controller){$this->userController = $controller;}public function login($telephone, $password){$startTimestamp = microtime(true);//委托$vo = $this->userController->login($telephone, $password);$endTimestamp = microtime(true);$this->metricsCollector = $endTimestamp - $startTimestamp;echo $this->metricsCollector .PHP_EOL;return $vo;}public function register($telephone, $password){$startTimestamp = microtime(true);//委托$vo = $this->userController->register($telephone, $password);$endTimestamp = microtime(true);$this->metricsCollector = $endTimestamp - $startTimestamp;echo $this->metricsCollector .PHP_EOL;return $vo;}
}
<?php
require __DIR__.'/vendor/autoload.php';$controller = new \App\UserControllerProxy(new \App\UserController());
$controller->login('boo','oob');
方法二(继承式)
如果原始类并没有定义接口,并且原始类代码并不是我们开发维护的(比如它来自一个第三方的类库),也没办法直接修改原始类,给它重新定义一个接口。
在这种情况下对于外部类的扩展,一般都是采用继承的方式。
完整代码 GitHub Gitee
原始类
<?phpnamespace App;/*** 原始类* Class UserController* @package App*/
class UserController
{/*** @param $telephone* @param $password* @return array*/public function login($telephone, $password){// 模拟执行时间usleep(100);echo 'login' . PHP_EOL;return [];}/*** @param $telephone* @param $password* @return array*/public function register($telephone, $password){// 模拟执行时间usleep(100);echo 'register' .PHP_EOL;return [];}
}
实现代理类
<?phpnamespace App;/*** 代理类* Class UserControllerProxy* @package App*/
class UserControllerProxy extends UserController
{protected $metricsCollector;public function login($telephone, $password){$startTimestamp = microtime(true);//调用父类$vo = parent::login($telephone ,$password);$endTimestamp = microtime(true);$this->metricsCollector = $endTimestamp - $startTimestamp;echo $this->metricsCollector .PHP_EOL;return $vo;}public function register($telephone, $password){$startTimestamp = microtime(true);//调用父类$vo = parent::register($telephone, $password);$endTimestamp = microtime(true);$this->metricsCollector = $endTimestamp - $startTimestamp;echo $this->metricsCollector .PHP_EOL;return $vo;}
}
调用代理类
<?phprequire __DIR__.'/vendor/autoload.php';$controller = new \App\UserControllerProxy(new \App\UserController());
$controller->login('boo','oob');
方法三 (动态代理)
以上的代码实现还存在以下问题:
- 需要在代理类中,将原始类中的所有的方法,都重新实现一遍,并且为每个方法都附加相似的代码逻辑。
- 如果要添加的附加功能的类有不止一个,我们需要针对每个类都创建一个代理类。
所谓动态代理(Dynamic Proxy
)就是不事先为每个原始类编写代理类,而是在运行的时候,动态地创建原始类对应的代理类,然后在系统中用代理类替换掉原始类。在PHP
中实现动态代理的底层依赖就是反射,通过反射可以获取类中所有的属性和方法,所以反射其实会破坏类的封装性。
参考代码 GitHub Gitee
<?php
namespace App;/*** 原始类* Class UserController* @package App*/
class UserController
{/*** @param $telephone* @param $password* @return array*/public function login($telephone, $password){// 模拟执行时间usleep(100);echo 'login' . PHP_EOL;return ['telephone' => $telephone,'password' => md5($password)];}/*** @param $telephone* @param $password* @return array*/public function register($telephone, $password){// 模拟执行时间usleep(100);echo 'register' .PHP_EOL;return ['telephone' => $telephone,'password' => md5($password)];}
}
<?php
namespace App;/*** 动态代理类* Class MetricsCollectorProxy* @package App*/
class MetricsCollectorProxy
{protected $metricsCollector;protected $reflection;protected $target;public function __construct(object $target){$this->target = $target;$this->reflection = new \ReflectionClass($target);}public function __call($name, $arguments){$startTimestamp = microtime(true);//委托$method = $this->reflection->getMethod($name);$vo = $method->invokeArgs($this->target,$arguments);$endTimestamp = microtime(true);$this->metricsCollector = $endTimestamp - $startTimestamp;echo $this->metricsCollector .PHP_EOL;return $vo;}}
<?php
require __DIR__.'/vendor/autoload.php';$controller = new \App\MetricsCollectorProxy(new \App\UserController());
$controller->login('boo','oob');
$controller->register('boo','oob');
其他参考
[1]. 极客时间《设计模式》(王争)
[2].《研磨设计模式》(陈臣、王斌)
[3]. 《Learning PHP设计模式》
[4]. 从零使用composer初始化PSR-4项目
[5]. https://time.geekbang.org/column/article/201823
[6] https://learnku.com/articles/34288
[7] https://learnku.com/articles/7538/the-application-of-reflection-in-php
[8] https://learnku.com/articles/37162
[9] https://gitee.com/obamajs/php-base-container/blob/master/Container.php
[10] https://www.php.net/manual/zh/book.reflection.php
我和王争学设计模式|代理模式相关推荐
- Python设计模式-代理模式
Python设计模式-代理模式 基于Python3.5.2,代码如下 #coding:utf-8info_struct = dict() info_struct["addr"] = ...
- Java设计模式(代理模式-模板方法模式-命令模式)
Java设计模式Ⅴ 1.代理模式 1.1 代理模式概述 1.2 静态代理 1.2.1 静态代理概述 1.2.2 代码理解 1.3 动态代理之JDK代理 1.3.1 动态代理之JDK代理概述 1.3.2 ...
- 设计模式——代理模式
设计模式--代理模式 代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能 ...
- 23种设计模式----------代理模式(一)
代理模式也叫委托模式. 代理模式定义:对其他对象提供一种代理从而控制对这个对象的访问.就是,代理类 代理 被代理类,来执行被代理类里的方法. 一般情况下,代理模式化有三个角色. 1,抽象的主题类(或者 ...
- java设计模式代理模式_Java中的代理设计模式
java设计模式代理模式 代理对象或代理对象为另一个对象提供占位符,以控制对该对象的访问. 代理充当原始对象的轻量级版本或简化版本. 它支持与原始对象相同的操作,但可以将那些请求委托给原始对象以实现它 ...
- 第四章 Caché 设计模式 代理模式
文章目录 第四章 Caché 设计模式 代理模式 定义 类型 使用场景 优点 缺点 结构图 完整示例 抽象主题类 真实主题类 代理类 对象类 调用 思考 第四章 Caché 设计模式 代理模式 定义 ...
- Android常见设计模式——代理模式(Proxy Pattern)(二)
文章目录 1. 前言 2. 远程代理(Remote Proxy) 3. 后记 1. 前言 在上篇Android常见设计模式--代理模式(Proxy Pattern)中基本上知道了什么是代理模式,以及对 ...
- sheng的学习笔记-设计模式-代理模式
原理图: 代理模式的定义:由于某些原因需要给某对象提供一个代理以控制对该对象的访问.这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介. 至少在以下集中情况下可以用 ...
- 设计模式-代理模式(Proxy Pattern)
设计模式-代理模式(Proxy Pattern) 文章目录 设计模式-代理模式(Proxy Pattern) 一.定义 二.概念解释 三.场景 四.实现 1.类图 2.代码实现 五.小结 六.动态代理 ...
- 简说设计模式——代理模式
一.什么是代理模式 关于代理模式,我们听到的见到的最多的可能就是静态代理.动态代理之类的,当然还有大家都知道的Spring Aop,这里我们先不谈这些个代理,先说个简单的例子.游戏代练应该都听说过,许 ...
最新文章
- TCP粘包问题 转自CSDN
- 性能测试工具MultiMechanize的使用介绍
- emacs c语言 自动补全,Emacs 与 C/C++ 代码自动补全
- Idea中搭建Wildfly(JBoss)运行环境(Mac)
- Chapter7-2_BERT and its family - Introduction and Fine-tune
- 用VC写Assembly代码(4)
- 正则的文字替换和字符串的替换哪个快_JavaScript正则表达式怎么用?
- activemq和kafka的区别
- Node.js视频教程
- matlab实现sift,SIFT算法的Matlab实现
- 西门子200PLC指令详解——位逻辑指令
- 东芝固态硬盘升级工具下载(软件+DMG)
- 微信小程序下拉刷新,上拉加载
- 基于PowerBuilder的病案统计系统的设计与实现
- 中文分词技术(一):规则分词
- jQuery 案例-图片抽奖
- c语言arg是什么函数,arg函数(arg辐角公式)
- Centos 安装Firefox
- 文本检测算法性能对比
- python绘制剖面图_Python气象绘图教程—(十九)剖面图