实战java设计模式(十三)代理模式

1 介绍

一个类代表另一个类的功能。

2 静态代理模式

2.1 例子

2.1.1 授课接口

//授课
interface Teach{
    void teach();
}

2.1.2 老师类

//老师类
class Teacher implements Teach{
    public void teach(){
        System.out.println("老师正在上课");
    }
}

2.1.3 代理老师(核心)

//代理上课
class TeacherProxy implements Teach{
    private InterFaceTeach target;//目标对象

    //构造方法
    TeacherProxy(InterFaceTeach target){
        this.target=target;
    }

    @Override
    public void teach() {
        System.out.println("代理开始");
        target.teach();//代理,表面是代理在教书,实际上是老师在教书
        System.out.println("代理结束");
    }
}

对外感觉是代理老师在上课,实际上代理老师还是找目标老师来上课的。注意和适配器模式的区别,适配器模式目标类没有实现要使用的接口,仅仅是适配器类在实现,而代理模式目标和代理都实现了要使用的接口。适配器的目标对象是继承或组合来的,而代理的目标对象是聚合来的。

2.1.4 测试主类

public class Main{
    public static void main(String[] args) {
        //代理前
        Teacher teacher=new Teacher();
        teacher.teach();
        //代理后
        TeacherProxy teacherProxy=new TeacherProxy(teacher);
        teacherProxy.teach();
    }
}

运行结果:

老师正在上课
代理开始
老师正在上课
代理结束

2.2 总结

静态代理方式的核心在于目标类和代理类都实现了同一个接口方法,然后代理类聚合目标类,对外看似使用代理的方法,实则使用的还是目标对象的方法。

3 动态代理

3.1 java反射

  • 使用动态代理需要有java反射的基础:java注解与反射
  • 动态代理需要使用的工具包:java.lang.reflect.Proxyjava.lang.reflect.InvocationHandler(基于接口)、cglib(基于类)、javasist(java字节码实现);
  • 动态代理的类是动态生成的,不是我们直接写好的;

3.2 基于接口的动态代理(JDK代理)

需要使用java.lang.reflect.Proxyjava.lang.reflect.InvocationHandler两个类;

3.2.1 InvocationHandler接口

  • 是一个接口;
  • 该仅仅只有一个方法:Object invoke(Object proxy, Method method, Object[] args),参数含义:proxy具体的代理实例,method代理实例的方法,args代理方法的参数列表,Object执行之后的返回结果对象;

每个代理实例都有一个关联的调用处理程序,当代理实例调用方法时,方法调用将被编码分配并分派到调用处理程序的invoke方法。

3.2.2 Proxy类

全是静态方法。

  • static InvocationHandler getInvocationHandler(Object proxy):返回代理的对象的InvocationHandler,用于执行代理方法。
  • static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces):返回代理类,传入类加载器和代理接口。
  • static boolean isProxyClass(Class<?> cl):判断一个类是不是代理类。
  • static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h):传入类加载器,类代理的接口,执行代理方法的接口。输出一个代理对象。

3.2.3 实现代理管理者类

// 代理管理者机构
class ProxyManager implements InvocationHandler{
    // 被代理的接口
    private Object target;

    //真实对象传进来
    public void setTarget(Object target) {
        this.target = target;
    }

    // 获得代理实例
    public Object getProxyInstance(){
        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("JDK代理开始");
        //利用反射机制调用目标对象的方法
        Object out=method.invoke(target,args);
        System.out.println("JDK代理提交");
        return out;
    }
}

注意点:当获取代理实例的时候,必须要有一个InvocationHandler的实现,当代理执行所有接口方法的时候,都会执行invoke实现的方法

3.2.4 测试主类

public class Main {
    public static void main(String[] args) {
        // 被代理对象
        Teacher teacher = new Teacher();
        // 创建代理
        ProxyManager proxyTeacher = new ProxyManager();
        // 把真正的老师设置进去
        proxyTeacher.setTarget(teacher);
        // 获得代理老师
        Teach instance = (Teach) proxyTeacher.getProxyInstance();
        // 执行方法
        instance.teach();
    }
}

注意点:动态代理精髓在于被代理对象可以是多变的,可就是动态的灵魂,而静态代理每代理一种类就要去实现一个代理类,也就是说ProxyManager这个模板是可以不动的,只需要setTarget()不同的被代理对象即可。

3.3 总结

静态代理的弊端是每新增一种代理,就需要编写实现一个代理类,比如学生代理,老师代理等等。而动态代理利用java的反射机制,只需要实现一个代理管理者,当需要代理不同的对象的时候,只需要把这个对象set进去即可,不需要再编写代理类,唯一要注意的就是jdk代理是基于接口实现的,所以这些被代理的对象都需要以实现接口的方式。

4 Cglib代理

待更新。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值