设计模式专题(四)——代理模式
(原创内容,转载请注明来源,谢谢)
一、概述
代理模式(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
相关阅读: