目录

  • 定义
  • 使用场景
  • 需求描述
  • 方法一(接口式)
  • 方法二(继承式)
  • 方法三 (动态代理)
  • 其他参考

极客时间《设计模式》(王争)

定义

为其他对象提供一种代理以控制对这个对象的访问

使用场景

在不改变原始类(或叫被代理类)代码的情况下,通过引入代理类来给原始类附加功能。比如:监控、统计、鉴权、限流、事务、幂等、日志。将这些附加功能与业务功能解耦,放到代理类统一处理,让程序员只需要关注业务方面的开发。除此之外,代理模式还可以用在 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

我和王争学设计模式|代理模式相关推荐

  1. Python设计模式-代理模式

    Python设计模式-代理模式 基于Python3.5.2,代码如下 #coding:utf-8info_struct = dict() info_struct["addr"] = ...

  2. Java设计模式(代理模式-模板方法模式-命令模式)

    Java设计模式Ⅴ 1.代理模式 1.1 代理模式概述 1.2 静态代理 1.2.1 静态代理概述 1.2.2 代码理解 1.3 动态代理之JDK代理 1.3.1 动态代理之JDK代理概述 1.3.2 ...

  3. 设计模式——代理模式

    设计模式--代理模式 代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能 ...

  4. 23种设计模式----------代理模式(一)

    代理模式也叫委托模式. 代理模式定义:对其他对象提供一种代理从而控制对这个对象的访问.就是,代理类 代理 被代理类,来执行被代理类里的方法. 一般情况下,代理模式化有三个角色. 1,抽象的主题类(或者 ...

  5. java设计模式代理模式_Java中的代理设计模式

    java设计模式代理模式 代理对象或代理对象为另一个对象提供占位符,以控制对该对象的访问. 代理充当原始对象的轻量级版本或简化版本. 它支持与原始对象相同的操作,但可以将那些请求委托给原始对象以实现它 ...

  6. 第四章 Caché 设计模式 代理模式

    文章目录 第四章 Caché 设计模式 代理模式 定义 类型 使用场景 优点 缺点 结构图 完整示例 抽象主题类 真实主题类 代理类 对象类 调用 思考 第四章 Caché 设计模式 代理模式 定义 ...

  7. Android常见设计模式——代理模式(Proxy Pattern)(二)

    文章目录 1. 前言 2. 远程代理(Remote Proxy) 3. 后记 1. 前言 在上篇Android常见设计模式--代理模式(Proxy Pattern)中基本上知道了什么是代理模式,以及对 ...

  8. sheng的学习笔记-设计模式-代理模式

    原理图: 代理模式的定义:由于某些原因需要给某对象提供一个代理以控制对该对象的访问.这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介. 至少在以下集中情况下可以用 ...

  9. 设计模式-代理模式(Proxy Pattern)

    设计模式-代理模式(Proxy Pattern) 文章目录 设计模式-代理模式(Proxy Pattern) 一.定义 二.概念解释 三.场景 四.实现 1.类图 2.代码实现 五.小结 六.动态代理 ...

  10. 简说设计模式——代理模式

    一.什么是代理模式 关于代理模式,我们听到的见到的最多的可能就是静态代理.动态代理之类的,当然还有大家都知道的Spring Aop,这里我们先不谈这些个代理,先说个简单的例子.游戏代练应该都听说过,许 ...

最新文章

  1. TCP粘包问题 转自CSDN
  2. 性能测试工具MultiMechanize的使用介绍
  3. emacs c语言 自动补全,Emacs 与 C/C++ 代码自动补全
  4. Idea中搭建Wildfly(JBoss)运行环境(Mac)
  5. Chapter7-2_BERT and its family - Introduction and Fine-tune
  6. 用VC写Assembly代码(4)
  7. 正则的文字替换和字符串的替换哪个快_JavaScript正则表达式怎么用?
  8. activemq和kafka的区别
  9. Node.js视频教程
  10. matlab实现sift,SIFT算法的Matlab实现
  11. 西门子200PLC指令详解——位逻辑指令
  12. 东芝固态硬盘升级工具下载(软件+DMG)
  13. 微信小程序下拉刷新,上拉加载
  14. 基于PowerBuilder的病案统计系统的设计与实现
  15. 中文分词技术(一):规则分词
  16. jQuery 案例-图片抽奖
  17. c语言arg是什么函数,arg函数(arg辐角公式)
  18. Centos 安装Firefox
  19. 文本检测算法性能对比
  20. python绘制剖面图_Python气象绘图教程—(十九)剖面图

热门文章

  1. 解决服务器终端无法显示图片的问题
  2. 超快速!10分钟入门Keras指南
  3. Occupancy Flow: 4D Reconstruction by Learning Particle Dynamics(2)
  4. SSH日期录入,日期精确不能精准到时分秒处理
  5. 在ubuntu下安装炉石传说
  6. 5G关键技术,D2D通信-ielab
  7. 2020010909
  8. iOS7+系统自带条码扫描
  9. 如何在CSS和HTML中创建垂直线...
  10. 旅游网-去哪儿网景点评论爬取