标签:
本文是在学习中的总结,欢迎转载但请注明出处:http://blog.csdn.net/pistolove/article/details/51550035
代理模式为另一个对象提供替身或占位符以控制对这个对象的访问。使用代理模式创建代表对象,让代表对象控制某对象的访问,被代理的对象可以是远程的对象、创建开销大的对象或需要安全控制的对象。(摘自Head First 中文版第460页)
代理模式中,代理类(proxy class)对它的客户隐藏了对象的具体信息。因此,在使用代理模式时,常常会在代理类中创建对象的实例;其主要在不改变接口的前提下,来“控制”对象的访问,“控制”占主导地位。相比于装饰者模式,装饰者模式将目标对象传入装饰类中,其主要是“扩展”功能。
大多数情况下,代理类和被代理对象是has-a关系(组合),除非代理类直接继承被代理类形成is-a关系(继承)。常用代理分为静态代理和动态代理。静态代理在随着时间的推移会出现问题,主要表现在如果类方法数量越来越多的时候,代理类的代码量是十分庞大的。其实在程序运行前就已经存在代理类的字节码文件,代理类和被代理类的关系在运行前就已经确定了。
动态代理则不会出现上面所述的问题。在动态代理中,动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以不存在代理类的字节码文件。代理类和被代理类的关系是在程序运行时确定。 Spring AOP可以算作是代理模式的一个典型应用,通过参数即可判断真实类,而无需事先实例化,这样可以实现解耦和代码灵活多变。
抽象角色:声明共同接口。这样,在任何可以使用目标对象的地方都可以使用代理对象。
代理角色:代理对象包含对目标对象的引用,在任何时候可操作目标对象;代理对象提供一个与目标对象相同的接口,以便可以在任何时候替代目标对象。
真实角色:代理对象所代表的目标对象,代理角色所代表的真实对象,其是最终要引用的对象。
静态代理代码示例如下所示:
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();
}
}
Java RMI(远程接口调用)中的stub对象就是代理对象,客户必须取得了stub对象才能给你调用其中的方法(具体情况不在此讲解感兴趣可以看看源码)。java.lang.reflect.Proxy也使用了代理模式,可以去看看源码学习学习。
动态代理的优点:动态代理类比较简洁,避免了创建多个不同静态代理的麻烦和重复多余的代码。调用目标代码时,在方法“运行时”动态的加入,更加灵活。
动态代理的缺点:系统变得灵活了,但是效率有所降低,其比静态代理慢一点。代码的可读性不好,不太容易理解。只能对实现了接口的类进行代理。
本文只是简单介绍了代理模式,并未对其进行深入探讨,略显粗糙。希望本文对你有所帮助。
标签:
原文地址:http://blog.csdn.net/pistolove/article/details/51550035