设计模式07_代理模式

Posted 皮斯特劳沃

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式07_代理模式相关的知识,希望对你有一定的参考价值。

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


1、定义

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


2、说明

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

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

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


3、角色

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

          代理角色:代理对象包含对目标对象的引用,在任何时候可操作目标对象;代理对象提供一个与目标对象相同的接口,以便可以在任何时候替代目标对象。

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


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也使用了代理模式,可以去看看源码学习学习。

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

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

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


以上是关于设计模式07_代理模式的主要内容,如果未能解决你的问题,请参考以下文章

用于从 cloudkit 检索单列的代码模式/片段

设计模式——代理模式

第07课:生活中的代理模式——帮我拿一下快递

代理模式(静态代理动态代理)代码实战(详细)

是否有在单个活动中处理多个片段的 Android 设计模式?

GO设计模式07代理模式