理解设计模式——代理模式

在这里插入图片描述

定义

    由于某些原因需要给对象提供一个代理以控制对该对象的访问,这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象目标对象之间的中介。

模式类型

    结构型设计模式

实现方法

静态代理

在这里插入图片描述

代码示例

//买房者
public interface Buyer {
    void buyHouse();
}

//私人
public class person implements Buyer{
    @Override
    public void buyHouse() {
        System.out.println("私人买房");
    }
}

//中介代理购房
public class proxy implements Buyer{

    private Buyer buyer;

    public proxy(Buyer buyer) {
        this.buyer = buyer;
    }

    @Override
    public void buyHouse() {
        //增强功能:快速筛选合适房屋
        System.out.println("筛选合适房屋");
        //增强功能:带看房
        System.out.println("带看房");
        buyer.buyHouse();
    }
}

//客户端调用
public class client {
    public static void main(String[] args) {
        person p = new person();
        proxy proxy = new proxy(p);
        proxy.buyHouse();
    }
}

客户端调用结果:

筛选合适房屋
带看房
私人买房

    上述为简单的静态代理,静态代理是代理对象和目标对象都需要实现同一接口。
        优点:可以在不修改目标对象的前提下扩展目标对象的功能。
        缺点:类数量变多了,并且在接口中新增方法,代理对象和目标对象都需要修改,扩展复杂。

JDK动态代理

在这里插入图片描述
代码示例

//买房者
public interface Buyer {
    void buyHouse();
}

//私人
public class person implements Buyer{
    @Override
    public void buyHouse() {
        System.out.println("私人买房");
    }
}

//反射代理
public class ProxyInvocationHandler<T> implements InvocationHandler {
    private T target;

    public ProxyInvocationHandler(T target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("增强功能");
        // 执行目标对象方法
        Object returnValue = method.invoke(target, args);
        return returnValue;
    }
}

//客户端调用
public class client {
    public static void main(String[] args) {
        Buyer p = new person();
        InvocationHandler proxyFactory = new ProxyInvocationHandler<Buyer>(p);
        Buyer buyer = (Buyer) Proxy.newProxyInstance(Buyer.class.getClassLoader(), new Class<?>[]{Buyer.class}, proxyFactory);
        buyer.buyHouse();
    }
}

客户端调用结果:

增强功能
私人买房

    上述则为JDK动态代理,可以发现在目标对象在新增、修改和删除方法时,代理类无需进行任何更改,并且任何的目标对象都可以使用该代理类进行代理,所有被代理方法都会在InvocationHandler中的invoke方法进行统一处理。
    JDK动态代理实现步骤如下:

  1. 存在目标对象和其接口。
  2. 创建InvocationHandler并在其invoke方法中,实现代理增强的逻辑。
  3. 调用Proxy.newProxyInstance方法,传入3个参数,分别是目标对象的接口类加载器,目标对象接口类和InvocationHandler实例。

    迷思小贴士:

     JDK动态代理在使用上存在一定的局限性,首先必须要确保被目标对象存在接口,其次被代理的方法只能是在接口中被声明的方法。但JDK动态代理无需引用任何外部依赖,JAVA原生支持。

CGLIB代理

代码示例

//超人(目标对象)无需实现接口
public class SuperPerson {
    public void buyHouse(){
        System.out.println("超人买房,不需要接口");
    }
}
//CGLIB代理类
public class CGProxy implements MethodInterceptor {
    private Object target;
    /**
     * 代理方法,实现增强逻辑
     */
    public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy proxy) throws Throwable {
        System.out.println("增强功能");
        Object result = proxy.invokeSuper(arg0, arg2);
        return result;
    }

    /**
     * 获取代理对象
     */
    public Object getProxyObject(Object target) {
        this.target = target;
        Enhancer enhancer = new Enhancer();
        // 设置代理对象
        enhancer.setSuperclass(this.target.getClass());
        // 设置回调(在调用父类方法时,回调 this.intercept())
        enhancer.setCallback(this);
        // 创建代理对象
        return enhancer.create();
    }
}
//客户端调用代理方法
public class Client {

    public static void main(String[] args) {
        SuperPerson superPerson = new SuperPerson();    // 被代理的对象
        // 创建代理对象(创建的代理对象可以放在容器中缓存,后续调用时获取即可)
        SuperPerson proxyObject = (SuperPerson) new CGProxy().getProxyObject(superPerson);
        proxyObject.buyHouse();
    }
}

    上述为CGLIB(Code Generation Library),是一个基于ASM的字节码生成库,允许我们在运行时对字节码进行修改和动态生成。CGLIB通过继承方式实现代理。CGLIB无需目标对象必须有接口,但需要引入额外的依赖包。代码中MethodInterceptor.intercept对目标对象的方法进行拦截代理,在Enhancer设置目标对象,从中获取到代理对象。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值