设计模式之代理模式

概述

代理模式是我们常用的设计模式之一。所谓的代理模式是指客户端并不直接调用实际的对象,而是通过调用代理对象,来间接的调用实际的对象,简单来说,就是不改变原有对象的情况下,对目标对象功能的扩展。代理模式主要注重的是过程。

应用场景

客户端不想直接与实际的对象交互,或者访问实际对象有困难,或者不属于客户端专业范围内,就需要通过代理对象来完成这项工作。

举个生活中的例子,小伙子刚来大城市打拼,需要租房子,自己找到合适的房子比较困难,正好中介手中有资源,小伙把房子要求告诉中介,中介根据要求提供小伙合适的房子,中介在这里就是一个代理对象。

静态代理

静态代理可以实现在不修改目标对象功能的前提下,对目标功能的扩展。

静态代理需要定义接口或者父类,代理对象和被代理对象需要实现相同接口或者继承相同父类。

下面用中介找房的做例子,代码示例:

1、定义找房接口:

public interface Handsome {

    void findHouse(String name);
}

2、目标对象接口:

public class HandsomeImpl implements Handsome {

    @Override
    public void findHouse(String name) {
        System.out.println("找个" + name + "的房子");
    }
}

3、代理对象接口

public class IntermediaryProxy implements Handsome {

    private Handsome handsome;

    public IntermediaryProxy(Handsome handsome) {
        this.handsome = handsome;
    }

    @Override
    public void findHouse(String name) {
        System.out.println("准备房源~");
        handsome.findHouse("找个" + name + "的房子");
        System.out.println("找到房子~");
    }
}

4、测试

public class Test {

    public static void main(String[] args) {
        Handsome handsome = new HandsomeImpl();
        Handsome proxySinger = new IntermediaryProxy(handsome);
        handsome.findHouse("一室一厨一卫");
    }
}

静态代理的缺点是代理对象需要实现和目标对象相同的接口,这样的话会产生很多的代理类,同时目标对象的接口每次需要增加,这样太过于繁琐。

动态代理

动态代理不需要代理对象实现父类的接口,通过实现Jdk或者Cglib的API接口,在内存中通过字节码重组的方式,对目标对象进行代理。

JDK代理

示例代码:

public class JdkProxy implements InvocationHandler {

    private Object target;

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("准备房源!");
        Object result = method.invoke(target, args);
        System.out.println("找到房子!");
        return result;
    }

    private Object getJdkProxy(Object targetObj) {
        this.target = targetObj;
        return Proxy.newProxyInstance(targetObj.getClass().getClassLoader(), targetObj.getClass().getInterfaces(), this);
    }

    public static void main(String[] args) {
        JdkProxy jdkProxy = new JdkProxy();
        Handsome handsome = (Handsome) jdkProxy.getJdkProxy(new HandsomeImpl());
        handsome.findHouse("一室一厨一卫");
    }
}

上述代码中主要使用newProxyInstance方法,且接收的三个参数依次为:

  • ClassLoader loader:指定当前目标对象使用类加载器,获取加载器的方法是固定的
  • Class<?>[] interfaces:目标对象实现的接口的类型,使用泛型方式确认类型
  • InvocationHandler h:事件处理,执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的方法作为参数传入

Cglib代理

示例代码:

public class CglibProxy implements MethodInterceptor {

    private Object target;

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("准备房源!");
        Object invoke = method.invoke(target, args);
        System.out.println("找到房子!");
        return invoke;
    }

    public Object getCglibProxy(Object objectTarget) {
        this.target = objectTarget;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(objectTarget.getClass());
        enhancer.setCallback(this);
        Object result = enhancer.create();
        return result;
    }

    public static void main(String[] args) {
        CglibProxy cglib = new CglibProxy();
        Handsome handsome = (Handsome) cglib.getCglibProxy(new HandsomeImpl());
        handsome.findHouse("一室一厨一卫");
    }
}

静态代理和Jdk代理模式都是要求目标对象是实现接口,而Cglib可以代理一个没有实现任何接口的目标对象。

示例代码:

1、目标对象

public class Handsome {

    public void findHouse(String name) {
        System.out.println("找个" + name + "的房子");
    }
}

2、代理对象

public class CglibProxy implements MethodInterceptor {

    private Object target;

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("准备房源!");
        Object invoke = method.invoke(target, args);
        System.out.println("找到房子!");
        return invoke;
    }

    public Object getCglibProxy(Object objectTarget) {
        this.target = objectTarget;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(objectTarget.getClass());
        enhancer.setCallback(this);
        Object result = enhancer.create();
        return result;
    }

    public static void main(String[] args) {
        CglibProxy cglib = new CglibProxy();
        Handsome handsome = (Handsome) cglib.getCglibProxy(new Handsome());
        handsome.findHouse("一室一厨一卫");
    }
}

这种动态代理应用在Spring Aop中,容器中的目标对象有实现接口用JDK代理,目标对象没有实现接口用Cglib代理,也可通过配置强制容器使用Cglib代理。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值