设计模式——代理模式

来源:互联网 发布:真正能借到钱的软件 编辑:程序博客网 时间:2024/06/15 14:51

模式介绍

代理模式:为其他对象提供一种代理以控制对这个对象的访问。
代理模式(Proxy)是一种结构型设计模式,主要解决的问题是:在直接访问对象时带来的问题.

分类

  • 静态代理:代理类是在编译时就实现好的。也就是说 Java 编译完成后代理类是一个实际的 class 文件。

  • 动态代理:代理类是在运行时生成的。也就是说 Java 编译完之后并没有实际的 class 文件,而是在运行时动态生成的类字节码,并加载到JVM中。

静态代理模式结构

模式涉及角色

RealSubject 是原对象(或称委托对象),ProxyObject是代理对象。
Subject 是委托对象和代理对象都共同实现的接口。
leave() 是委托对象和代理对象共同拥有的方法。

结构图

这里写图片描述
(图片来自网络,侵删)

示例

比如某人要请假,因为有事不能直接去请假,可以找个同事(代理对象)帮他请假。

代码实现

/** * ClassName: ProxyPattern <br/> * Function: 静态代理和动态代理<br/> * * @author gary.liu * @date 2017/5/23 */public class ProxyPattern {    public static void main(String[] args){        /**         * 静态代理测试         */        RealSubject realSubject = new RealSubject();  //委托对象        ProxyObject proxyObject = new ProxyObject(realSubject);  //代理对象        proxyObject.leave();    }}interface Subject{    /**     * 请假接口     */    void leave();}class RealSubject implements Subject {    @Override    public void leave(){        System.out.println("RealSubject leave request");    }}class ProxyObject implements Subject {    private Subject subject;    public ProxyObject(Subject subject){        this.subject = subject;    }    @Override    public void leave(){        System.out.println("真正对象告诉代理帮他请假");        subject.leave();        System.out.println("代理告诉真正对象请假成功");    }}

动态代理

动态代理的思维模式与之前的一般模式是一样的,也是面向接口进行编码,创建代理类将具体类隐藏解耦,不同之处在于代理类的创建时机不同,动态代理需要在运行时因需实时创建.

模式结构

和上面类似,需要一个接口和实现了这个接口的真实对象类,然后还要自己定义一个类(调用处理器类,即实现 InvocationHandler 接口),这个类的目的是指定运行时将生成的代理类需要完成的具体任务(包括Preprocess和Postprocess),即代理类调用任何方法都会经过这个调用处理器类。

结构图

这里写图片描述
(图片来自网络,侵删)

代码实现

用动态代理实现上面的场景,需要自定义一个调用处理器类。

public class ProxyPattern {    public static void main(String[] args){        /**         * 动态代理测试         */        ProxyHandler proxyHandler = new ProxyHandler(realSubject);        //动态生成代理对象        Subject proxySubject = (Subject) Proxy.newProxyInstance(RealSubject.class.getClassLoader(), RealSubject.class.getInterfaces(),                proxyHandler);        proxySubject.leave();    }}/** * 动态代理实现上面的例子 * */class ProxyHandler implements InvocationHandler {    private Subject subject;    public ProxyHandler(Subject subject){        this.subject = subject;    }    @Override    public Object invoke(Object proxy, Method method, Object[] args){        Object result = null;        System.out.println("真正对象告诉代理帮他请假");        try{            result = method.invoke(subject, args);        } catch (Exception e){            e.printStackTrace();        }        System.out.println("代理告诉真正对象请假成功");        return result;    }}

jdk动态代理为什么要求委托对象实现接口

//创建代理对象  static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)

第二个参数是接口,表明这个代理类需要实现哪些接口。
因为 Java 的单继承特性(每个代理类都继承了 Proxy 类),只能针对接口创建代理类,不能针对类创建代理类。

手动生成的代理类写入字节数组中

        byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy1", RealSubject.class.getInterfaces());

然后写入class文件,用 jd-gui反编译生产的代理类如下。

public final class $Proxy1 extends java.lang.reflect.Proxy implements com.lzhenxing.javascaffold.javabase.designpattern.Subject {

模式应用

代理模式用到的地方很多,比如 spring aop 使用的便是动态代理模式,spring aop 有两种实现方式,一种是jdk动态代理(要求委托对象实现接口);另一种是字节码增强,委托对象可以不实现接口,具体实现如 cglib。

参考资料

代理模式及Java实现动态代理

《大话设计模式》

原创粉丝点击