程序员人生 网站导航

设计模式07_代理模式

栏目:php教程时间:2016-06-03 19:10:54

          本文是在学习中的总结,欢迎转载但请注明出处:http://blog.csdn.net/pistolove/article/details/51550035


1、定义

          代理模式为另外一个对象提供替身或占位符以控制对这个对象的访问。使用代理模式创建代表对象,让代表对象控制某对象的访问,被代理的对象可以是远程的对象、创建开消大的对象或需要安全控制的对象。(摘自Head First 中文版第460页)


2、说明

          代理模式中,代理类(proxy class)对它的客户隐藏了对象的具体信息。因此,在使用代理模式时,常常会在代理类中创建对象的实例;其主要在不改变接口的条件下,来“控制”对象的访问,“控制”占主导地位。相比于装潢者模式,装潢者模式将目标对象传入装潢类中,其主要是“扩大”功能。

          大多数情况下,代理类和被代理对象是has-a关系(组合),除非代理类直接继承被代理类构成is-a关系(继承)。经常使用代理分为静态代理和动态代理。静态代理在随着时间的推移会出现问题,主要表现在如果类方法数量愈来愈多的时候,代理类的代码量是10分庞大的。其实在程序运行前就已存在代理类的字节码文件,代理类和被代理类的关系在运行前就已肯定了。

          动态代理则不会出现上面所述的问题。在动态代理中,动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以不存在代理类的字节码文件。代理类和被代理类的关系是在程序运行时肯定。 Spring AOP可以算作是代理模式的1个典型利用,通过参数便可判断真实类,而无需事前实例化,这样可以实现解耦和代码灵活多变。


3、角色

          抽象角色:声明共同接口。这样,在任何可使用目标对象的地方都可使用代理对象。

          代理角色:代理对象包括对目标对象的援用,在任什么时候候可操作目标对象;代理对象提供1个与目标对象相同的接口,以即可以在任什么时候候替换目标对象。

          真实角色:代理对象所代表的目标对象,代理角色所代表的真实对象,其是终究要援用的对象。


4、类图

这里写图片描述


5、示例

          静态代理代码示例以下所示:

package headfirst.design.proxy; public interface Itraget { public void say(); }
package headfirst.design.proxy; public class TargetObject implements Itraget { @Override public void say() { System.err.println("I want to say something"); } }
package headfirst.design.proxy; public class PorxyObject implements Itraget{ private Itraget target; PorxyObject() { this.target = new TargetObject(); } @Override public void say() { this.target.say(); } }
package headfirst.design.proxy; public class Test { public static void main(String[] args) { Itraget pItraget = new PorxyObject(); pItraget.say(); } }

          动态代理代码示例以下所示:

package headfirst.design.JDKproxy; public interface ITarget { public void update(); }
package headfirst.design.JDKproxy; public class ConcreateTarget implements ITarget { @Override public void update() { System.err.println("I am jdk proxy"); } }
package headfirst.design.JDKproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class PorxyHandle implements InvocationHandler { private Object target; public Object bind(Object obj) { target = obj; return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object obj = null; obj = method.invoke(target, args); return obj; } }
package headfirst.design.JDKproxy; public class Test { public static void main(String[] args) { PorxyHandle handle = new PorxyHandle(); ITarget tItraget = (ITarget) handle.bind(new ConcreateTarget()); tItraget.update(); } }

6、总结

          Java RMI(远程接口调用)中的stub对象就是代理对象,客户必须获得了stub对象才能给你调用其中的方法(具体情况不在此讲授感兴趣可以看看源码)。java.lang.reflect.Proxy也使用了代理模式,可以去看看源码学习学习。

          动态代理的优点:动态代理类比较简洁,避免了创建多个不同静态代理的麻烦和重复过剩的代码。调用目标代码时,在方法“运行时”动态的加入,更加灵活。

          动态代理的缺点:系统变得灵活了,但是效力有所下降,其比静态代理慢1点。代码的可读性不好,不太容易理解。只能对实现了接口的类进行代理。

          本文只是简单介绍了代理模式,并未对其进行深入探讨,略显粗糙。希望本文对你有所帮助。


------分隔线----------------------------
------分隔线----------------------------

最新技术推荐