以下内容转自: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();
这种代理模式也最为简单,就是通过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();
于是你的代理模型会变成这样:
毫无疑问,仅仅为了扩展同样的功能,在方案一种,我们会重复创建多个逻辑相同,仅仅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'); ?>
优点是日志等操作非常简便,对所有的方法都可以用一个动态代理来完成操作,对原代码没有入侵性。
其缺点也比较容易体现,由于过于通用,动态代理在方法和属性的细节控制上就会较为繁琐,滥用会导致系统复杂性增高,若操作的细节过多还可能明显影响性能。