设计模式之代理模式

921 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第19天,点击查看活动详情

简介

定义:

为其他对象提供一种代理以控制对这个对象的访问

代理模式的定义比较简洁,可能不熟悉代理模式的同学比较难以理解,但是对于大部分学后台的同学应该对代理模式还是比较熟悉的。简单来说就是为已有对象通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。

在我们生活中也能经常见到代理模式的出现,差不多有关代理的都是一种代理模式。比如委托律师打打官司,律师就是对委托人的代理,然后很多外国产品在国内的代理商,等等。由此可见经过代理之后,代理类相对于委托类是由增强的和改动的。

案例

那我们通过代码中来看,代理模式要怎么实现。代理一般分为静态代理和动态代理。

静态代理

定义一个【人】的接口,它有一个【说话】的接口

public interface IPerson {
    void speak();
}

然后定义一个法外狂徒张三去实现IPerson

public class Zhangsan implements IPerson {
    @Override
    public void speak() {
        System.out.println("zhangsan speak");
    }
}

这个时候法外狂徒张三犯事了,找了个代理律师帮他辩护。那律师要怎么了解这个案件呢,需要那些个张三来给他描述下案件,所以要将某个张三(IPerson)注入进来。

public class Lawyer implements IPerson {
    private IPerson person;
    public Lawyer(IPerson person) {
        this.person = person;
    }
    @Override
    public void speak() {
        System.out.println("lawyer speak start");
        person.speak();
        System.out.println("lawyer speak end");
    }
}

那既然是要给张三辩护,那把张三传进来给律师说道说道吧

public class App {
    public static void main(String[] args) {
        Lawyer lawyer = new Lawyer(new Zhangsan());
        lawyer.speak();
    }
}

静态代理还是比较简单的,可能我们很多同学平时都用过这个模式,但是并没有意识到这是静态代理。

JDK动态代理

动态代理的玩法相对复杂一点,主要依赖于InvocationHandler这个类。新建一个JdkProxy类,新增一个newProxy方法,用于创建代理类,主要是这个方法比较关键,大家要多关注这个方法,及时不好理解,暂时记住把。然后还要重写invoke方法,对委托类进行功能增强。

public class JdkProxy implements InvocationHandler {
    private Object target;

    public Object newProxy(Object target) {
        this.target = target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("proxy start");
        Object invoke = method.invoke(target, args);
        System.out.println("proxy end");
        return invoke;
    }
}

应用类就很简单了,直接直接创建一个代理类然后调用方法即可。

public class App {
    public static void main(String[] args) {
        JdkProxy jdkProxy = new JdkProxy();
        IPerson o = (IPerson)jdkProxy.newProxy(new Zhangsan());
        o.speak();
    }
}

CGlib动态代理

CGlib动态代理是针对类实现代理,对指定的类生成一个子类,并覆盖其中的方法,这种通过继承类的实现方式。但是这种方式不能代理final修饰的类。

总结

静态代理相对来说还是比较好理解的,通过一个构造注入委托类即可实现代理类的增强。而JDK动态代理则需要熟悉理解InvocationHandler这个类才能真正熟悉这种模式,至于CGlib动态代理则通过通过实现MethodInterceptor接口实现,在spring新的版本中使用比较多,我们后续再详细介绍。