静态代理与动态代理的理解与适用范围

以下内容转自:https://blog.csdn.net/wangqyoho/article/details/77584832

----------------------------------------------------

静态代理通常用于对原有业务逻辑的扩充。比如持有二方包的某个类,并调用了其中的某些方法。然后出于某种原因,比如记录日志、打印方法执行时间,但是又不好将这些逻辑写入二方包的方法里。所以可以创建一个代理类实现和二方方法相同的方法,通过让代理类持有真实对象,然后在原代码中调用代理类方法,来达到添加我们需要业务逻辑的目的。

这其实也就是代理模式的一种实现,通过对真实对象的封装,来实现扩展性。

一个典型的代理模式通常有三个角色,这里称之为**代理三要素**

共同接口

public interface Action {
    public void doSomething();
}

真实对象

public class RealObject implements Action{

    public void doSomething() {
        System.out.println("do something");
    }
}

代理对象

public class Proxy implements Action {
    private Action realObject;

    public Proxy(Action realObject) {
        this.realObject = realObject;
    }
    public void doSomething() {
        System.out.println("proxy do");
        realObject.doSomething();
    }
}

运行代码

    Proxy proxy = new Proxy(new RealObject());
    proxy.doSomething();

simple_proxy.png

这种代理模式也最为简单,就是通过proxy持有realObject的引用,并进行一层封装。

静态代理的优点和缺点

先看看代理模式的优点: 扩展原功能,不侵入原代码。

再看看这种代理模式的缺点:

假如有这样一个需求,有十个不同的RealObject,同时我们要去代理的方法是不同的,比要代理方法:doSomething、doAnotherThing、doTwoAnotherThing,添加代理前,原代码可能是这样的:

realObject.doSomething();
realObject1.doAnotherThing();
realObject2.doTwoAnother();

为了解决这个问题,我们有方案一:

为这些方法创建不同的代理类,代理后的代码是这样的:

proxy.doSomething();
proxy1.doAnotherThing();
proxy2.doTwoAnother();

当然,也有方案二:

通过创建一个proxy,持有不同的realObject,实现Action1、Action2、Action3接口,来让代码变成这样:

proxy.doSomething();
proxy.doAnotherThing();
proxy.doTwoAnother();

于是你的代理模型会变成这样:

dynamic_proxy.png

毫无疑问,仅仅为了扩展同样的功能,在方案一种,我们会重复创建多个逻辑相同,仅仅RealObject引用不同的Proxy。

而在方案二中,会导致proxy的膨胀,而且这种膨胀往往是无意义的。此外,假如方法签名是相同的,更需要在调用的时候引入额外的判断逻辑。


动态代理:以下内容引用自https://blog.csdn.net/san_er/article/details/22212023,有修改。

<?php  
header('Content-Type: text/html;charset=utf-8');


/*2014-03-26 
*根据反射API实现了简单的动态代理,真正操作类是mysql类。但是通过sqlprozy类实现了根据动态传入参数,代替实际的运行的类。在具体运行当中需要根据实际情况来使用,不要滥用反射,反射的消耗也比较大。 
平时一般情况下有两个方面用到1:对对象进行调试2:获取类的信息。 
*/  
class mysql{  
    function connect($db){  
        echo "连接到数据库1",$db[0],"\r\n";  
    }  
}
class mysql2{  
    function connect($db){  
        echo "连接到数据库2",$db[0],"\r\n";  
    }  
}
class sqlproxy{  
    private $target;  
    function __construct($tar){
        if (is_array($tar)) {
            foreach ($tar as $obj) {
                $this->tar[] = new $obj();
            }
            var_dump($this->tar);
        }
    }  
    function __call($name,$args){  
        foreach($this->target as $obj){  
            $r = new ReflectionClass($obj);  
            if($method=$r->getMethod($name)){  
                if($method->ispublic() && !$method->isAbstract()){  
                    $method->invoke($obj,$args);  
                }  
            }  
        }  
    }  
}  

$obj = new sqlproxy(['mysql', 'mysql2']);  
$obj->connect('member');  
?>  

优点是日志等操作非常简便,对所有的方法都可以用一个动态代理来完成操作,对原代码没有入侵性。

其缺点也比较容易体现,由于过于通用,动态代理在方法和属性的细节控制上就会较为繁琐,滥用会导致系统复杂性增高,若操作的细节过多还可能明显影响性能。

猜你喜欢

转载自blog.csdn.net/dxcyber409/article/details/80242641