代理模式-java

108 阅读3分钟

代理模式

有天狗蛋在网上买了件黑丝,快递到了狗蛋忙着当王者荣耀,没空去拿于是狗蛋叫了个跑腿帮他拿快递,哎....这有没有代理的味道呢?狗蛋还让跑腿帮他带包烟 666 啊。

其实生活中有很多代理模式的影子,代理模式起到一个中介的作用,例如我们要买房子怎么办呢?当然是找中介了,那这个中介就是代理对象啦。

代理模式的结构:

  1. 抽象主题:声明真实主题和代理要实现的方法
  2. 真实主题:实现抽象主题 (目标对象,其实就是要被代理的类啦)
  3. 代理类:实现抽象主题 (代理对象)

我们分析一下,狗蛋和跑腿要做的事情是不是同一件事呢?当然了都是拿快递嘛...中介和卖房子的客户他们要做事情都是卖房子啊。既然大家一样的目标,所以真实主题和代理类都要实现抽象主题接口啦。

在这个例子中:抽象主题角色是Subject接口,真实主题角色是GetPackage类,代理类角色是Proxy类,这里边代理类角色充当了跑腿小哥,狗蛋是调用者,如果狗蛋自己调用目标对象(真实主题类)的方法,相当于自己去拿快递,如果调用代理对象(代理类)的方法就是叫了跑腿啦。

***********************静态代理模式实现 *******************

代理模式类图:

0004.png

抽象主题代码

/**
 * 抽象主题类:这个接口是目标对象(真实主题类)和 代理对象(代理类)都要共同实现的接口
 */
public interface Subject {
    // 拿快递的方法
    void getExpress();
}

真实主题代码

/**
 * 具体主题:(目标对象)
 */
public class GetPackage implements Subject{
    // 拿快递的方法
    @Override
    public void getExpress() {
        System.out.println("拿了快递...");
    }
}

代理类代码

/**
 * 代理类
 */
public class Proxy implements Subject {
    // 聚合目标对象
    private GetPackage getPackage = new GetPackage();

    // 拿快递的方法
    @Override
    public void getExpress() {
       // 拿快递
       getPackage.getExpress();
       // 帮客户买烟
       System.out.println("买了一包电杆(中华的别名)...");
    }
}

测试代码

public class Test {
    public static void main(String[] args) {
        // 创建代理对象
        Proxy proxy = new Proxy();

        // 执行方法
        proxy.getExpress();
    }
}

运行结果

001.png

***********************jdk动态代理模式实现 *******************

下面使用jdk动态代理,代理类就由java来维护了,我们使用java提供的Proxy.newProxyInstance()方法来获取代理对象。静态代理中代理类在编译期就已经确定,而动态代理则是JVM运行时动态生成。

抽象主题代码

/**
 * 抽象主题类:这个接口是(真实主题)目标对象和(代理类)代理对象都要共同实现的接口
 */
public interface Subject {
    // 定义拿快递的方法
    void getExpress();
}

真实主题代码

/**
 * 具体主题:(目标对象)
 */
public class GetPackage implements Subject{
    // 实现了拿快递的方法
    @Override
    public void getExpress() {
        System.out.println("拿了快递...");
    }
}

代理工厂类

// 代理工厂
public class ProxyFactory {
    // 聚合具体主题
    private GetPackage getPackag = new GetPackage();

    // 获取代理对象
    public Subject getProxy() {
        return (Subject) Proxy.newProxyInstance(
                GetPackage.class.getClassLoader(),     // 目标对象类加载器
                GetPackage.class.getInterfaces(),      // 接口的字节码
                new InvocationHandler(){
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        /**
                         * Object proxy:代理对象,这个参数我们一般不用
                         * Method method:要去调用目标类的哪个方法
                         * Object[] args:方法的参数
                         */

                        // 通过反射去调用目标对象的方法
                        Object result = method.invoke(getPackag, args);

                        // 帮客户买烟
                        System.out.println("拿买了一包电杆(中华的别名)...");

                        // 如果要调用的方法有返回值,就返回真实的返回值,没有返回值,就返回null
                        return result;
                    }
                }
        );
    }
}

代理模式的应用场景:例如防火墙当数据包进出我们的电脑的时候,代理模式在中间可以帮我们做一些鉴别数据包是否有害。spring aop 中也是代理模式思想实现的面向切面编程,可以动态为方法进行增强。

动态代理还有一种实现方式CGlib感兴趣的可以自行学习。