设计模式——代理模式

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

目录

介绍

代理模式(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中提供了一个动态代理类ProxyProxy并不是我们上述所说的代理对象的类,而是提供了一个创建代理对象的静态方法(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. 虚拟代理: 用于管理占用大量资源的对象的创建过程,比如加载图像、视频等。通过代理来推迟资源的加载,直到需要时才加载。

代理模式的优缺点

优点

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

缺点

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

总结

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

相关推荐
toto4129 分钟前
Java中的锁机制 与 synchronized的理解
java·算法
潜意识起点10 分钟前
使用 JDBC 实现 Java 数据库操作
java·开发语言·数据库
sleepybear111311 分钟前
JetBrains IDEA 2024 在使用 lombok 后构建失败/编译失败解决方案
java·ide·intellij-idea·软件构建
莫名其妙小饼干28 分钟前
时间管理系统|Java|SSM|JSP|
java·开发语言·maven·mssql
越甲八千35 分钟前
重拾设计模式--外观模式
c++·设计模式·外观模式
苹果酱056738 分钟前
【react项目】从零搭建react项目[nodejs安装]
java·spring boot·毕业设计·layui·课程设计
岁月变迁呀1 小时前
长轮询DeferredResult原理
java·spring
数据小小爬虫1 小时前
如何利用Java爬虫获得Lazada商品评论列表
java·开发语言
西岭千秋雪_1 小时前
设计模式の享元&模板&代理模式
java·设计模式·代理模式·享元模式·模板方法模式
越甲八千1 小时前
重撸设计模式--代理模式
设计模式·代理模式