设计模式专题(四)——代理模式

设计模式专题(四)——代理模式

(原创内容,转载请注明来源,谢谢)

一、概述

代理模式(Proxy)是为其他对象提供一种代理,以控制这个对象的访问。即外系统需要调用系统内部的服务,都要通过代理。这个模式在RPC架构中非常常用。

1)使用场景

代理模式在项目中使用广泛。

1.远程代理。即将proxy文件放置于公共部分,作为真正提供接口的地方,而实际实现接口不在此文件中。这样实现远程访问的功能。

2.虚拟代理。如果需要创建一个开销很大的对象,可以用代理模式,用它来存放实例化需要很长时间的真实对象。例如打开一个网页,里面有大量图片,通常页面会先加载出来,图片再慢慢的刷出来,这就是用到了代理模式。因此,代理模式通常会结合单例模式。

3.安全代理。通过代理模式用来控制真实对象访问的权限,把需要提供的接口对外提供,而不是提供全部的功能。

4.智能指引。当调用真实的对象,代理处理另外一件事情。例如检查对象是否是持久对象,检查对象是否已经锁定,检查对象是否没有使用可以释放。

2)意义

1.保密性

代理模式,通过引入一个新的对象,来实现对真实对象的操作或者将新的对象作为真实对象的一个替身。它可以在客户端和目标对象之间起到中介的作用,并且可以通过代理对象去掉客户不能看到的内容和服务或者添加客户需要的额外服务。

2. 延迟加载

当还没使用一个类的实例时,先实例化的是代理类,然后在真正使用的时候才去实例化正式的类。因此,延迟加载主要有两个意义:首先,它可以在时间轴上分散系统压力,尤其在系统启动时,不必完成所有的初始化工作,从而加速启动时间;其次,对很多真实场景而言,在软件启动直到被关闭的整个过程中,可能根本不会被调用,初始化这些数据无疑是一种资源浪费。例如框架在执行的时候会加载很多的代理,应对各种操作(例如各个子系统的调用),不同的操作会触发不同的代理,但是对于具体的某种操作只会触发部分的代理而不会触发全部代理,因此就可以起到节约时间的作用。

3. 动态代理

动态代理是指不必为每一个真实的服务文件写一个代理类,而是只写一个类,通常可以通过魔术方法__call来实现动态代理。

二、UML类图

三、功能实现

1)业务场景

使用代理模式对外部提供服务接口,实现动态代理,对外部进开放proxy。现对外提供若干字符串处理服务,现假设有字符串加密校验、多维数组替换字段。

2)实现逻辑

1.抽象一个类,用于给其他类继承。

2.实现proxy类,作为代理模式的核心,作为代理,其中定义__call方法给其他代码动态调用。

3.实现service类,完成具体的功能。

4.实现client类,调用proxy,实现接口调用。

3)代码实现

<?php
//代理模式
//抽象类
abstract class StringDealer{
         public static functiongetInstance(){}
}
//client,调用proxy获取结果
class StringDealerClient{
         private $strToDeal;
         public function__construct($str){
                   $this->strToDeal= $str;
                   return$this;
         }
         public function__call($name, $args=''){
                   if(empty($args)){
                            $args= $this->strToDeal;
                   }
                   $strProxy =StringDealerProxy::getInstance();
                   return$strProxy->$name($args);
         }
}
//proxy
class StringDealerProxy extends StringDealer{
         private static $ins;//代理自己的的实例
         private $svcIns;//服务StringDealerService的实例
         private function__construct(){}
         private function__clone(){}
         public static functiongetInstance(){
                   if(null ==self::$ins || !(self::$ins instanceof self)){
                            self::$ins= new StringDealerProxy();
                   }
                   returnself::$ins;
         }
         public function__call($name, $args){
                   if(null ==$this->svcIns || !($this->svcIns instanceof $StringDealerService)){
                            $this->svcIns= new StringDealerService();
                   }       
                   //判断类的方法是否存在,不存在则返回null
                   if(!method_exists($this->svcIns,$name)){
                            returnnull;
                   }
                   //存在则执行方法返回结果
                   return$this->svcIns->$name($args);
         }       
}
//实现类
class StringDealerService extends StringDealer{
         public functionsecretCheck($str){
                   $str =$str[0];
                   $str =md5($str. 'stringdealer');
                   //调用数据库获取加密后的字段,省略代码
                   $sqlStr ='xx';
                   return $str== $sqlStr;
         }
         public functionmutiArrayReplace($strToRep, $strReped, $arr){
                   if(!is_array($arr)){
                            returnstr_replace($strToRep, $strReped, $arr);
                   }
                   //含有特殊字符,无法将数组转成json进行字符串替换
                   if(in_array($strToRep,array("'", '"', '(', ')', '[', ']', '{', '}', ':'))){
                            foreach($arras &$item){
                                     if(is_array($item)){
                                               $item= $this->mutiArrayReplace($strToRep, $strReped, $item);
                                     }else{
                                               $item= str_replace($strToRep, $strReped, $item);
                                     }
                            }
                   }else{
                            $arrStr= json_encode($arr);
                            $arrStr= str_replace($strToRep, $strReped, $arrStr);
                            $arr= json_decode($arrStr);
                   }
                   return$arrStr;
         }
}
$strDealer = new StringDealerClient('abcd');
echo $strDealer->secretCheck();

——written by linhxx 2017.07.29

相关阅读:

设计模式专题(三)——装饰模式

设计模式专题(二)——策略模式

设计模式专题(一)——面向对象的设计原则

原文发布于微信公众号 - 决胜机器学习(phpthinker)

原文发表时间:2017-07-29

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏大内老A

[WCF 4.0新特性] 标准终结点与无(.SVC)文件服务激活

今天介绍WCF 4.0的另外两个新特性:标准终结点(Standard Endpoint)和无(.SVC)文件服务激活(File-Less Activation)...

23410
来自专栏漏斗社区

工具| 诸神之眼nmap定制化之并发处理

当我们使用nmap来进行大规模探测的时候,速度和准确度是摆在我们面前的两个问题,这时需要考虑到nmap的并发处理能力。 0x01 nmap本身的并发执行 相关...

3685
来自专栏北京马哥教育

Linux 内存中的 Cache 真的能被回收么?

在 Linux 系统中,我们经常用 free 命令来查看系统内存的使用状态。在个 RHEL6 的系统上,free 命令的显示内容大概是这样一个状态: ? 这里...

4605
来自专栏阮一峰的网络日志

什么是 Event Loop?

Event Loop 是一个很重要的概念,指的是计算机系统的一种运行机制。 JavaScript语言就采用这种机制,来解决单线程运行带来的一些问题。 ? ...

2888
来自专栏高性能服务器开发

(一)Redis结构解析

从今天起,本人将会展开对Redis源码的学习,Redis的代码规模比较小,非常适合学习,是一份非常不错的学习资料,数了一下大概100个文件左右的样子,用的是C...

2814
来自专栏Java技术栈

Maven Optional & Exclusions使用区别

Optional和Exclusions都是用来排除jar包依赖使用的,两者在使用上却是相反。 Optional定义后,该依赖只能在本项目中传递,不会传递到引用该...

3299
来自专栏Debian社区

Linux 系统 vim 编辑器使用简明教程

vi(vim)是上Linux非常常用的代码编辑器,很多Linux发行版都默认安装了vi(vim)。vi(vim)命令繁多但是如果使用灵活之后将会大大提高效率。v...

1217
来自专栏全沾开发(huā)

使用postman进行API自动化测试

使用postman进行API自动化测试 最近在进行一个老项目的升级,第一步是先将node版本从4.x升级到8.x,担心升级会出现问题...

5577
来自专栏用户2442861的专栏

深入Python(2): __init__.py 用法

原文:http://www.2cto.com/kf/201204/129388.html python的每个模块的包中,都有一个__init__.py文...

831
来自专栏编程

并发服务器(三):事件驱动

另一种常见的实现并发的方法叫做 事件驱动编程,也可以叫做 异步 编程 。这种方法变化万千,因此我们会从最基本的开始,使用一些基本的 API 而非从封装好的高级方...

2845

扫码关注云+社区