Java设计模式之代理模式

本文详细介绍了代理模式的概念及其在Java中的应用,包括静态代理和动态代理(JDK动态代理及Cglib动态代理)的实现方式,并提供了具体的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

代理模式

proxy

代理模式可以分为静态代理和动态代理

静态代理

租房例子

在这里插入图片描述

角色

大话设计模式角色结构图

在这里插入图片描述

  • 抽象角色:一般会使用接口抽象类来解决(租房)
  • 真实角色(被代理对象或目标对象):被代理的角色(房东)
  • 代理角色(代理对象):代理真实角色,代理真实角色后,会做一些附属操作(中介)
  • 客户:访问代理对象的人(我们,租房的人)
代理模式租房代码

结构图

在这里插入图片描述

抽象角色(接口)

/**
 * @author Tc.l
 * @Date 2021/1/26
 * @Description:抽象角色 租房
 */
public interface AbstractRole {
    //出租
    void rent();
}

真实角色

/**
 * @author Tc.l
 * @Date 2021/1/26
 * @Description:真实角色 房东
 */
public class RealRole implements AbstractRole{
    @Override
    public void rent() {
        System.out.println("房东出租房屋......");
    }
}

代理角色

/**
 * @author Tc.l
 * @Date 2021/1/26
 * @Description:代理角色 中介
 */
public class ProxyRole implements AbstractRole{
    //通过接口聚合 房东
    private AbstractRole houseMaster;

    public ProxyRole(AbstractRole houseMaster) {
        this.houseMaster = houseMaster;
    }

    //帮房东出租房子
    @Override
    public void rent() {
        seeHouse();
        qianHeTong();
        houseMaster.rent();
    }

    private void seeHouse(){//看房
        System.out.println("帮客户看房子");
    }

    private void qianHeTong(){//签合同
        System.out.println("跟客户签合同");
    }

}

客户端

/**
 * @author Tc.l
 * @Date 2021/1/26
 * @Description:
 */
public class Client {
    public static void main(String[] args) {
        //房东
        RealRole houseMaster = new RealRole();

        //中介
        ProxyRole zhongjie = new ProxyRole(houseMaster);
        zhongjie.rent();
    }
}
/*
帮客户看房子
跟客户签合同
房东出租房屋......
*/

我看不到房东,但我依旧通过代理(中介)租到的房东的房子,这就是所谓的代理模式 中间加了一层代理角色

我没有直接调用房东的rent方法而是通过代理角色去调用

总结

使用的关键

  1. 真实角色,代理角色 要实现同一个接口(抽象角色)
  2. 接口要聚合代理角色,通过构造器将真实角色传给代理角色,方便调用

静态代理优缺点

优点:

  • 不修改真实角色功能的情况下,可以使用代理角色去扩展功能 (比如代码中的扩展功能: 看房子和签合同)

  • 可以使真实角色更加纯粹,不用去关注一些公共业务(房东只用管租房不用去签合同,看房之类)

  • 公共业务交给代理角色,实现了业务的分工

  • 公共业务发生扩展的时候,方便集中管理

缺点:

  • 一个真实角色会产生一个代理角色,代码量翻倍,开发效率变低
  • 接口增加方法时,真实角色与代理角色都要维护

动态代理

  • 动态代理的角色和静态代理一样
  • 动态代理的代理类是动态生成的,静态代理的代理类是我们提前写好的
  • 动态代理分为俩类:一类是基于类的动态代理,一类是基于接口的动态代理
    • 基于接口的动态代理——JDK动态代理
    • 基于类的动态代理——cglib
JDK动态代理

JDK动态代理需要了解俩个类

核心:Proxy (代理)与 InvocationHandler(调用处理程序)

Proxy

在这里插入图片描述

InvocationHandler(调用处理程序)

在这里插入图片描述

角色代码

抽象角色

/**
 * @author Tc.l
 * @Date 2021/1/26
 * @Description:抽象角色 租房
 */
public interface AbstractRole {
    //出租
    void rent();
}

真实角色

/**
 * @author Tc.l
 * @Date 2021/1/26
 * @Description:
 */
public class RealRole implements AbstractRole {
    @Override
    public void rent() {
        System.out.println("房东出租房屋......");
    }
    
}

动态生成代理角色

/**
 * @author Tc.l
 * @Date 2021/1/26
 * @Description:
 */
public class ProxyFactory implements InvocationHandler {
    //真实角色 被代理类
    private Object realRole;

    public ProxyFactory(Object realRole) {
        this.realRole = realRole;
    }

    //动态获得代理类
    public Object getProxy(){
        /*
       Proxy.newProxyInstance方法参数如下
       ClassLoader loader:     加载真实角色的类加载器
       Class<?>[] interfaces:  真实角色实现的接口(获取要代理的抽象角色)
       InvocationHandler h:    调用处理程序,调用接口方法时会来调用 InvocationHandler的invoke方法
       (在invoke方法中通过反射调用接口方法,还可以在invoke方法中增加其他方法功能,类似静态代理中的代理角色实现的接口方法)
        * */
        return Proxy.newProxyInstance(realRole.getClass().getClassLoader()
                ,realRole.getClass().getInterfaces()
                //因为ProxyFactory实现了InvocationHandler接口所以填this 事件处理时按照实现的invoke执行
                ,this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        /*
        * proxy:代理角色实例
        * method:代理角色调用的接口方法
        * args:method方法的参数
        * */
        seeHouse();
        Object result = method.invoke(realRole, args);
        qianHeTong();
        return result;
    }


    private void seeHouse(){//看房
        System.out.println("帮客户看房子");
    }

    private void qianHeTong(){//签合同
        System.out.println("跟客户签合同");
    }
}

客户端测试

/**
 * @author Tc.l
 * @Date 2021/1/26
 * @Description:
 */
public class Client {
    public static void main(String[] args) {
        //房东
        RealRole houseMaster = new RealRole();

        //动态代理得到代理角色
        ProxyFactory proxyFactory = new ProxyFactory(houseMaster);
        AbstractRole proxy = (AbstractRole) proxyFactory.getProxy();

        //调用代理角色的方法
        proxy.rent();
    }
}
/*
帮客户看房子
房东出租房屋......
跟客户签合同
*/
总结

在这里插入图片描述

JDK动态代理好处(静态代理的好处它都有):

  • 使真实角色更纯粹,不去关注其他公共事情
  • 公共的业务由代理来完成,实现了业务的分工
  • 公共业务发生扩展时变得更加集中和方便
  • JDK动态代理可以代理多个类,代理的是接口(一类业务)
Cglib动态代理

有时候真实角色只是一个单独对象未实现接口,这是可以使用Cglib动态代理

Cglib动态代理在内存中构建一个真实角色的子类对象从而实现对真实角色的功能扩展,也被称为子类代理

特点: 真实角色(被代理类)不用实现接口

角色代码

导入Cglib依赖

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.3.0</version>
</dependency>

真实角色

public class RealRole {
    public void rent(){
        System.out.println("出租房子.....");
    }
}

cglib动态获得代理类

public class ProxyFactory implements MethodInterceptor {
    //真实角色 被代理类
    private Object realRole;

    public ProxyFactory(Object realRole) {
        this.realRole = realRole;
    }

    //获得代理角色(代理类)
    public Object getProxyInstance(){
        //1.使用工具类
        Enhancer enhancer = new Enhancer();
        //2.设置真实角色为代理角色的父类
        enhancer.setSuperclass(realRole.getClass());
        //3.设置回调函数
        enhancer.setCallback(this);
        //4.创建代理角色
        return enhancer.create();
    }

    private void seeHouse(){//看房
        System.out.println("帮客户看房子");
    }

    private void qianHeTong(){//签合同
        System.out.println("跟客户签合同");
    }

    //类似JDK动态代理中 InvocationHandler 的invoke
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        seeHouse();
        Object result = method.invoke(realRole, args);
        qianHeTong();
        return result;
    }
}

客户端测试租房

public class Client {
    public static void main(String[] args) {
        //真实角色
        RealRole houseMaster = new RealRole();

        //cglib动态代理 获得代理类
        ProxyFactory proxyFactory = new ProxyFactory(houseMaster);
        RealRole proxy = (RealRole) proxyFactory.getProxyInstance();

        //租房
        proxy.rent();
    }
}
/*
帮客户看房子
出租房子.....
跟客户签合同
*/

结构图

在这里插入图片描述

总结

Cglib获得代理角色:

  1. 获得代理角色要实现MethodInterceptor
  2. 使用工具类Enhancer获得代理类(设置父类,设置回调,创建)
  3. 重写MethodInterceptor接口的intercept方法,可以在该方法中扩展其他功能

真实角色不用实现接口,Cglib是基于类的动态代理,代理类是被代理类的子类(代理角色是真实角色的子类)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值