设计模式——代理模式

设计模式------代理模式

目录

介绍

代理模式(Proxy Pattern)是一种结构型设计模式,它允许通过代理对象来控制对某个对象的访问。代理模式主要用于在不改变原对象的情况下,控制对其的访问,或在访问时添加一些附加功能。

基本结构

在代理模式中,有三个主要角色:

  1. Subject(主题):定义了一个接口,这个接口可以是真实主题类和代理类都可以实现的接口。通常,它是代理和实际对象都必须实现的共同接口。
  2. RealSubject(真实主题):实现了 Subject 接口,通常是真正的业务对象,包含了代理模式所需要代理的具体操作。
  3. Proxy(代理类):代理类也实现了 Subject 接口,它通常会持有一个 RealSubject 的引用,并且可以在请求到达 RealSubject 之前或之后,执行一些额外的操作,如权限验证、延迟加载、日志记录等。

实现

静态代理

静态代理是在编译时就确定了代理类和真实类的关系,通常代理类和真实类有相同的接口。静态代理的代理类在运行时直接委托给真实对象实现具体操作。

示例代码:

  1. Subject(主题)

    java 复制代码
    // Subject 接口
    public interface Subject {
        void request();
    }
  2. RealSubject(真实主题)

    java 复制代码
    // RealSubject 类
    public class RealSubject implements Subject {
        @Override
        public void request() {
            System.out.println("RealSubject request");
        }
    }
  3. Proxy(代理类)

    java 复制代码
    // Proxy 类
    public class Proxy implements Subject {
        private RealSubject realSubject;
    
        public Proxy(RealSubject realSubject) {
            this.realSubject = realSubject;
        }
    
        @Override
        public void request() {
            System.out.println("Proxy request before");
            realSubject.request();
            System.out.println("Proxy request after");
        }
    }
  4. 测试代码(客户端)

    java 复制代码
    // 客户端代码
    public class Client {
        public static void main(String[] args) {
            RealSubject realSubject = new RealSubject();
            Proxy proxy = new Proxy(realSubject);
            proxy.request();
        }
    }

    以上述为例,我们可以清楚看到,通过代理,轻松实现在调用具体目标方法前后补充内容。具体补充的内容由业务决定(权限校验,日志记录等等),只需要在Proxy中修改request()方法中的逻辑即可

动态代理

动态代理是在运行时由代理类自动生成的,常常利用 Java 反射机制和 Proxy 类来创建代理对象。动态代理在开发中更加灵活,通常不需要在编译时明确指定代理类。这里注意:Java中提供了一个动态代理类Proxy,Proxy并不是我们上述所说的代理对象的类,而是提供了一个创建代理对象的静态方法(newProxyInstance方法)来获取代理对象。

示例代码:

  1. Subject(主题)

    java 复制代码
    //卖票接口
    public interface SellTickets {
        void sell();
    }
  2. RealSubject(真实主题)

    java 复制代码
    //火车站  火车站具有卖票功能,所以需要实现SellTickets接口
    public class TrainStation implements SellTickets {
    
        public void sell() {
            System.out.println("火车站卖票");
        }
    }
  3. 动态代理类(重点理解)

    java 复制代码
    //代理工厂,用来创建代理对象
    public class ProxyFactory {
    
        private TrainStation station = new TrainStation();
    
        // 获取代理对象
        public SellTickets getProxyObject() {
            //使用Proxy获取代理对象
            /*
                newProxyInstance()方法参数说明:
                    ClassLoader loader : 类加载器,用于加载代理类,使用真实对象的类加载器即可
                    Class<?>[] interfaces : 真实对象所实现的接口,代理模式真实对象和代理对象实现相同的接口
                    InvocationHandler h : 代理对象的调用处理程序
             */
            SellTickets sellTickets = (SellTickets) Proxy.newProxyInstance(station.getClass().getClassLoader(),
                    station.getClass().getInterfaces(),
                    new InvocationHandler() {
                        /*
                            InvocationHandler中invoke方法参数说明:
                                proxy : 代理对象
                                method : 对应于在代理对象上调用的接口方法的 Method 实例
                                args : 代理对象调用接口方法时传递的实际参数
                         */
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
                            System.out.println("代理点收取一些服务费用(JDK动态代理方式)");
                            // 执行真实对象
                            // 这里执行的是真实主题中的sell()方法
                            // 第一个参数就是真实主题对象,第二个是真是主题中对应方法的参数
                            Object result = method.invoke(station, args);
                            return result;
                        }
                    });
            return sellTickets;
        }
    }
  4. 测试代码(客户端)

    java 复制代码
    //测试类
    public class Client {
        public static void main(String[] args) {
            //获取代理对象
            ProxyFactory factory = new ProxyFactory();
            
            SellTickets proxyObject = factory.getProxyObject();
            proxyObject.sell();
        }
    }

    通过动态代理,我们也可以轻松实现对某些方法的加强,不过可能会对技术要求高些。(由于需要结合大量代码进行解释,我就只能在代码中以注释的形式进行解释,这里就不再多说了)

应用场景

代理模式的应用场景

  1. 延迟加载(Lazy Loading): 代理模式可以用于延迟加载对象,只有在需要时才创建真实对象。例如,图像加载、数据库连接等。
  2. 权限控制: 在一些场景下,代理可以控制对某些资源的访问。代理可以在请求到达真实对象之前,检查客户端是否有访问权限。
  3. 日志记录: 代理模式可以在实际方法执行之前或之后进行日志记录。这对于监控、调试或审计应用程序行为很有帮助。
  4. 远程代理: 在分布式系统中,代理模式常用来表示一个远程对象,通过代理对远程对象的调用进行透明处理,隐藏了远程通信的细节。
  5. 虚拟代理: 用于管理占用大量资源的对象的创建过程,比如加载图像、视频等。通过代理来推迟资源的加载,直到需要时才加载。

代理模式的优缺点

优点:

  • 可以控制访问:通过代理可以在访问真实对象前后加入额外的控制逻辑,如权限验证、日志记录等。
  • 提高性能:代理可以延迟加载资源,避免在不必要时加载或执行耗时操作。
  • 扩展功能:可以在不修改真实对象的情况下,扩展其功能(例如,添加缓存、日志等)。

缺点:

  • 增加复杂性:代理模式引入了额外的代理对象和复杂的类结构,可能使代码更复杂。
  • 性能开销:代理模式可能会引入额外的开销,因为每次对真实对象的操作都需要通过代理对象来转发。

总结

代理模式是一种通过代理对象控制对实际对象的访问的设计模式,它非常灵活,可以在许多场景中提高代码的可维护性和扩展性。代理可以用于日志记录、延迟加载、权限控制、性能优化等场景。

相关推荐
非优秀程序员8 小时前
第04章 邮箱大战,163 与 QQ 的暗战|《互联网产品恩仇录》
java·vue.js·架构
知已难寻9 小时前
Docker 入门:容器技术与 Docker 基础
java·运维·服务器·docker·云原生·容器
沐晓时光9 小时前
C语言入门,内存函数知识讲解
c语言·开发语言
文丑颜不良啊11 小时前
LeetCode2481~2500题目解析
java·leetcode
Flynn Liang12 小时前
同一需求三套写法:用 Spring AI、LangChain4j、AgentScope Java 各实现一个带工具调用的 RAG 助手(实战对比)
java·人工智能·大模型·架构设计·spring ai·langchain4j·agentscope
聪明的笨猪猪12 小时前
实际工程问题:AI 生成 Spring Cache(@Cacheable / @CachePut / @CacheEvict)缓存注解踩坑
java·经验分享·面试·ai编程
愿有所息13 小时前
记一次 ARM64 + JDK8 上 fastjson2 的诡异数据错乱
java
秋饼13 小时前
MCP 2026-07-28 无状态协议大改版:Spring AI 2.1 多轮往返请求与网关路由落地
java·ai·技术分享·后端开发
SL_staff14 小时前
JVS-BI 实战:业务人员如何用零代码 ELT + 可视化配置构建实时经营分析闭环
java·spring·全栈
SL_staff15 小时前
企业AI落地难?JVS-AI渐进式实践:安全可控、小切口验证、标准化沉淀与规模化复制
java·开源·aigc