设计模式——代理模式

代理模式

概念:为对象提供一个替身,控制目标对象(被代理对象)的访问,通过代理对象访问目标对象,好处是:可以在目标对象的基础上,增加功能、扩展功能。
分类
  • 静态代理:目标类(被代理类)和代理类都要实现共同接口。
  • 动态代理(也称JDK代理):目标类(被代理类)要实现接口,代理类不用实现接口。
  • Cglib代理:可以在内存中动态创建对象,不用实现接口。

1.静态代理:

介绍:静态代理要求目标类和代理类都要实现相同的接口。并且将目标对象聚合到代理对象中。

例子:有一个Teacher接口,接口中有一个teach方法,teacherA实现了Teacher接口,proxyTeacher也实现了Teacher接口。我们假设一个场景,当teacherA因为某些原因不能上课,我们可以用proxyTeacher去代替teacherA去上课,并且还可以在teacherA的讲课基础上进行扩展

共同接口

public interface Teacher {
    void teach();//讲课方法
}

(目标类)被代理类

public class teacherA implements Teacher {

    public teacherA() {
    }

    @Override
    public void teach() {
        System.out.println("正在上课");
    }
}

代理类

public class proxyTeacher implements Teacher {

    private  Teacher target;//目标对象()

    public proxyTeacher(Teacher target) {
        this.target = target;
    }

    @Override
    public void teach() {
        System.out.println("静态代理开始");
        teacher.teach();//使用目标对象去调用方法,此语句上面和下面可以写增强代码,实现功能的扩展。在这里我这增加了两句话,根据实际场景课进行扩展
        System.out.println("静态代理结束");
    }
}

Client类

public class Client {
    public static void main(String[] args) {
        //创建目标对象(被代理对象)
        teacherA target = new teacherA();
        //创建代理对象,同时将被代理对象作为参数传递给代理对象
        proxyTeacher proxyTeacher = new proxyTeacher(target);
        proxyTeacher.teach();//通过代理类调用teach()


    }
}

运行结果:通过代理对象调用teach(), 在teacherA中的teach()只打印了一句话正在上课,这里通过代理对象调用新增了两句话,这里就体现了代理模式对原来对象的基础上进行扩展,在实际场景可具体编写要扩展的代码

在这里插入图片描述

静态代理的优缺点:

优点:在不改变目标对象(被代理对象)的前提下,可以通过代理对象进行功能扩展。

缺点:很容易想到因为代理类和目标类(被代理类)实现了共同的接口,会增加维护成本,当接口要增加方法时,目标对象和代理对象所在的类都要进行维护。

2.动态代理(JDK代理)

介绍:目标类(被代理类)要实现接口,代理类不用实现接口。代理对象是利用JDK的API,动态的在内存中创建代理对象。

通过java.lang.reflect.Proxy包下的方法

public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,
                                      InvocationHandler h)

参数1 ClassLoader loader:在使用中传递一个(目标类)被代理类对象的类加载器。

参数2:Class<?>[] interfaces:获取(目标类)被代理类实现的接口。

参数3:InvocationHandler接口是proxy代理实例的调用处理程序实现的一个接口,每一个动态代理类的调用处理程序都必须实现InvocationHandler接口。此接口中有一个invoke()方法,在动态代理模式中要对此方法进行重写。当我们通过动态代理对象调用一个方法时候,将原来方法和相关的参数作为参数传入了此方法,实际调用了此方法。

例子:同静态代理中的例子

接口

public interface Teacher {

    void teach();
   
}

目标类(被代理类)

public class teacherA implements Teacher {
  
  @Override
    public void teach() {
        System.out.println("正在上课");
    }

}

代理类

public class ProxyTeacher {

    private Object target;

    public ProxyTeacher(Object target) {
        this.target = target;
    }

	
    public Object getProxyInstance(){

		//关键点在此方法,通过Proxy.newProxyInstance()创建代理对象。
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
            
            @Override                           //将方法作为参数传入,teach()就是一个方法对象
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("动态代理模式开始");
                
   //调用target对象的方法,args为方法参数的数组,因为teach()为void类型所以没有返回参数。         
                Object obj = method.invoke(target, args);
                
                System.out.println("动态代理模式开始");
                return obj;
            }
        });
    }

}

Client类

    public static void main(String[] args) {
        //创建目标对象
        teacherA target = new teacherA();
        //创建代理对象
        ProxyTeacher proxyFactory = new ProxyTeacher(target);
		//注意强转为Teacher类型
        Teacher proxyInstance = (Teacher)proxyFactory.getProxyInstance();
        //通过代理对象调用方法
        proxyInstance.teach();

    }

运行结果:
在这里插入图片描述

Cglib代理(子类代理)

介绍:不用实现接口,使用目标类(被代理类)的子类对象实现代理,但因为采用的是继承,所以不能对final修饰的类进行Cglib代理。

Cglib:是一个强大的代码生成包,可以在运行期扩展Java类与实现Java接口,经常用于AOP框架。

实现Cglib代理:要导入cglib的jar文件。

例子:同上面例子,用Cglib代理模式进行更改。

目标类:

public class Teacher {

    public String teach(){
        System.out.println("正在上课");
        return "hello";
    }

}

代理类:

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
//代理类要实现MethodInterceptor接口
public class proxyTeacher implements MethodInterceptor {
    private Teacher target;

    public proxyTeacher(Teacher teacher) {
        this.target = teacher;
    }

    public Object getProxyInstance(){
    //,Enhancer动态的创建给定类的子类并且拦截代理类的所有的方法
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());//设置目标对象
        enhancer.setCallback(this);//设置回调对象,在调用中拦截对目标方法的调用
        return enhancer.create();//创建代理对象,并返回
    }
    
    
	//在调用原方法之前会调用该方法,拦截对目标方法的调用
    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("Cglib代理开始");
        Object obj = method.invoke(target, args);
        System.out.println("Cglib代理结束");

        return  obj;
    }
}

Client类:

public class Client {
    public static void main(String[] args) {
    //创建目标对象
        Teacher target = new Teacher();
        //获取代理对象
        Teacher proxyInstance = (Teacher)new proxyTeacher(target).getProxyInstance();
       //调用方法
       proxyInstance.teach();

    }
}

运行结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值