设计模式-结构型之代理(proxy)模式

定义
  • 让代理负责完成工作,在必要的时候生成实例(实际主体)。
  • 增强被代理对象的功能。
使用场景
  • 只有真正需要生成实例的时候,才生成和初始化实例。
  • 实现对功能的增强(比如Spring 中的AOP)。
UML图在这里插入图片描述
三种方式
  • 静态代理
    – 特点:代理对象和目标对象实现同一接口。
    – 优点:不修改目标对象的情况下,能够使用代理对象对功能进行扩展。
    – 缺点:代理对象和实际主体都需要实现同一个接口,当接口增加功能,两者都需要维护。
  • 动态代理
    – 特点:代理对象无需实现接口,动态创建代理对象;目标对象必须实现接口。
    – 优点:代理对象无需实现接口,在需要的时候来动态的生成代理对象,从而对功能进行加强。
    – 缺点:被代理的对象必须是一个接口类型,否则无法生成代理对象。
  • cglib动态代理
    – 特点:目标对象无需实现接口。
    – 优点:被代理对象无需实现任何接口。方式是构建目标对象的一个子类,从而实现对功能的扩展。
    – 缺点:被代理的类不能被final 修饰。
代码实现
  • 静态代理
//主体:subject:使代理对象和被代理对象具有一致性
public interface ITeacher {

    public void teach();
}
//实际主体
public class Teacher implements ITeacher {
    @Override
    public void teach() {
        System.out.println("老师在授课中");
    }
}
//代理对象:调用实际主体,并进行功能增强
public class TeacherProxy implements ITeacher {

    private ITeacher teacher;

    public TeacherProxy(ITeacher teacher){
        this.teacher = teacher;
    }

    @Override
    public void teach() {
        before();
        teacher.teach();
    }

    public void before(){
        System.out.println("准备材料");
    }
}
public class Client {
    public static void main(String[] args) {
        Teacher teacher = new Teacher();
        TeacherProxy proxy = new TeacherProxy(teacher);
        proxy.teach();
    }
}
  • 动态代理
//主体
public interface ITeacher {
    public void teach();
}
//实际主体
public class Teacher implements ITeacher {
    @Override
    public void teach() {
        System.out.println("老师在授课中");
    }
}
//代理工厂:生成代理对象,并对目标方法功能增强
public class ProxyFactory {

    //获取代理对象方法
    //ITeacher teacher: 目标对象
    //@return 代理对象
    public Object getProxy(ITeacher teacher){

        // 增强目标对象的方法
        InvocationHandler invocationHandler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                before();
                // 调用目标对象方法
                Object o = method.invoke(teacher, args);
                return o;
            }
        };

        // 使用java 的Proxy 来动态创建代理对象
        //ClassLoader loader:生成代理对象的类加载器
        //Class<?>[] interfaces: 目标对象的接口类型
        //InvocationHandler h: 方法处理器
        return Proxy.newProxyInstance(teacher.getClass().getClassLoader(),
                teacher.getClass().getInterfaces(), invocationHandler);
    }

    public void before(){
        System.out.println("准备材料");
    }
}
// 测试
public class Client {
    public static void main(String[] args) {
        ITeacher teacher = new Teacher();
        ProxyFactory proxyFactory = new ProxyFactory();
        ITeacher proxy = (ITeacher) proxyFactory.getProxy(teacher);
        proxy.teach();
    }
}
  • cglib代理
//实际主体
public class Teacher {
    public void teach() {
        System.out.println("老师在授课中");
    }
}

/*代理对象工厂:需要导入cglib 相关包
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
*/
public class CglibProxyFactory<T> implements MethodInterceptor {
	//使用泛型,复用性更高
    private T t;

    public CglibProxyFactory(T t) {
        this.t = t;
    }

    public Object getProxy(){
        //创建工具类
        Enhancer enhancer = new Enhancer();
        //设置父类
        enhancer.setSuperclass(t.getClass());
        //设置回调函数:因为MethodInterceptor 继承了 Callback, 所以可以传参 this
        enhancer.setCallback(this);
        //创建代理对象
        return enhancer.create();
    }

    /**
     * @param o 代理对象
     * @param method 被拦截的方法
     * @param args   方法参数
     * @param methodProxy 被拦截方法代理
     * @return 目标方法返回值
     * @throws Throwable
     */
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("方法执行前");
        Object value = method.invoke(t, args);
        System.out.println("方法执行前后");
        return value;
    }
}
// 测试
public class Client {

    public static void main(String[] args) {
        CglibProxyFactory<Teacher> proxyFactory = new CglibProxyFactory<Teacher>(new Teacher());

        Teacher proxy = (Teacher) proxyFactory.getProxy();
        //cglib拦截所有的方法调用(包括从Object中继承的toString和hashCode方法)
        System.out.println(proxy);
        proxy.teach();
    }
}
总结
  • 让代理负责完成工作,在必要的时候生成目标实例。
  • 通过代理来实现对功能的增强。
  • 从静态代理-动态代理-cglib代理,其实就是一个优化的过程,提高代码扩展性和适用性。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值