关于代理模式的理解

系列文章

关于时间复杂度o(1), o(n), o(logn), o(nlogn)的理解

关于HashMap的哈希碰撞、拉链法和key的哈希函数设计

关于JVM内存模型和堆内存模型的理解

关于代理模式的理解

关于Mysql基本概念的理解

关于软件设计模式的理解


前言

代理模式常见的使用场景包括:

需要对对象的访问进行控制或限制的情况。
需要在访问对象时执行额外的操作,例如记录日志、收集统计信息等。。

一、代理模式的定义和优、缺点

定义

代理模式的定义可以概括为:为一个对象提供一个代理对象,以控制对该对象的访问。

优点

1. 访问控制: 代理模式可以在客户端和原始对象之间添加一层间接层,从而实现对原始对象的访问控制。这使得代理对象可以限制客户端对原始对象的直接访问,从而保护原始对象的安全性。

2. 增强原始对象功能: 代理模式允许在访问原始对象时执行额外的操作,例如记录日志、验证用户权限、实现懒加载、缓存结果等。这些额外的功能可以在代理对象中实现,而不需要修改原始对象的代码,从而使得原始对象的功能得到增强。

3. 远程访问: 通过远程代理,客户端可以像调用本地对象一样调用远程对象,而不需要了解网络通信的细节。这使得在分布式系统中使用远程对象变得更加简单和透明。

4. 性能优化: 代理模式可以通过实现缓存代理或虚拟代理来优化系统的性能。例如,缓存代理可以缓存频繁访问的操作结果,从而减少重复计算,提高系统的响应速度。

缺点

1.复杂性增加: 引入代理对象会增加系统的复杂性,因为需要额外的类和接口来实现代理功能。这可能会增加代码量和维护成本。

2.性能损耗: 在某些情况下,代理模式可能会引入额外的性能损耗,特别是在远程代理或虚拟代理的情况下,由于需要进行网络通信或延迟加载,可能会导致一定的性能损耗。

3.可能引入单点故障: 在使用远程代理时,代理对象可能会成为系统的单点故障。如果代理对象出现故障或不可用,可能会导致客户端无法访问远程对象。

4.过多的代理类: 如果系统中存在大量的代理类,可能会导致类的数量过多,增加系统的复杂性和管理成本。

二、代码演示案例

1.静态代理

需要为每一个代理类都手动编写一个对应的代理类。代码如下(示例):

// 接口
interface Subject {
    void request();
}

// 真实主题类
class RealSubject implements Subject {
    public void request() {
        System.out.println("RealSubject: Handling request.");
    }
}

// 代理类
class ProxySubject implements Subject {
    private RealSubject realSubject;

    public ProxySubject(RealSubject realSubject) {
        this.realSubject = realSubject;
    }

    public void request() {
        System.out.println("ProxySubject: Logging before request.");
        realSubject.request();
        System.out.println("ProxySubject: Logging after request.");
    }
}

// 测试类
public class Main {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        ProxySubject proxySubject = new ProxySubject(realSubject);

        proxySubject.request();
    }
}

2.JDK动态代理

在动态代理中,要求目标类必须实现接口,然后通过 Proxy 类和 InvocationHandler 接口动态生成代理对象。代码如下(示例):

import java.lang.reflect.*;

// 接口
interface Subject {
    void request();
}

// 真实主题类
class RealSubject implements Subject {
    public void request() {
        System.out.println("RealSubject: Handling request.");
    }
}

// 动态代理处理器类
class DynamicProxyHandler implements InvocationHandler {
    private Object target;

    public DynamicProxyHandler(Object target) {
        this.target = target;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("DynamicProxy: Logging before request.");
        Object result = method.invoke(target, args);
        System.out.println("DynamicProxy: Logging after request.");
        return result;
    }
}

// 测试类
public class Main {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        InvocationHandler handler = new DynamicProxyHandler(realSubject);

        Subject proxySubject = (Subject) Proxy.newProxyInstance(
                realSubject.getClass().getClassLoader(),
                realSubject.getClass().getInterfaces(),
                handler
        );

        proxySubject.request();
    }
}

3.CGLIB动态代理

CGLIB通过继承目标类来生成代理类的,因此无法代理目标类中的final方法和私有方法。代码如下(示例):

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

// 需要代理的目标类
class TargetClass {
    public void doSomething() {
        System.out.println("TargetClass: Doing something...");
    }
}

// 自定义方法拦截器
class CustomMethodInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("Before invoking method: " + method.getName());
        Object result = proxy.invokeSuper(obj, args); // 调用目标方法
        System.out.println("After invoking method: " + method.getName());
        return result;
    }
}

public class Main {
    public static void main(String[] args) {
        // 创建 Enhancer 对象,用于动态创建目标类的子类
        Enhancer enhancer = new Enhancer();
        // 设置目标类的父类
        enhancer.setSuperclass(TargetClass.class);
        // 设置方法拦截器
        enhancer.setCallback(new CustomMethodInterceptor());
        // 创建代理对象
        TargetClass proxy = (TargetClass) enhancer.create();
        
        // 调用代理对象的方法
        proxy.doSomething();
    }
}

总结

每种代理方式都有自己的适用场景和局限性。静态代理适用于简单场景下的代理,但不够灵活;JDK动态代理适用于需要在运行时动态生成代理对象,并且目标类实现了接口的情况;而CGLIB动态代理则适用于对未实现接口的类进行代理。选择合适的代理方式需要根据具体的需求和场景来决定。

  • 19
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
代理模式是一种结构型设计模式,它允许将对象的访问控制委托给另一个对象。在代理模式中,代理对象控制着原始对象的访问,并可以在原始对象的方法执行前或后添加自定义逻辑。以下是一个简单的 Java 代码示例,演示了如何使用代理模式: ```java // 定义一个接口 interface Image { void display(); } // 定义一个实现了 Image 接口的具体类 class RealImage implements Image { private String fileName; public RealImage(String fileName) { this.fileName = fileName; loadFromDisk(); } @Override public void display() { System.out.println("Displaying " + fileName); } private void loadFromDisk() { System.out.println("Loading " + fileName); } } // 定义一个代理类 class ProxyImage implements Image { private RealImage realImage; private String fileName; public ProxyImage(String fileName) { this.fileName = fileName; } @Override public void display() { if (realImage == null) { realImage = new RealImage(fileName); } realImage.display(); } } // 使用代理类访问实际对象 public class ProxyPatternDemo { public static void main(String[] args) { Image image = new ProxyImage("test_image.jpg"); // 在第一次访问时,会创建实际的对象并加载它 image.display(); // 在第二次访问时,不会创建实际的对象,而是直接访问代理对象 image.display(); } } ``` 在上面的示例中,`Image` 是一个接口,包含 `display()` 方法。`RealImage` 是一个实现 `Image` 接口的具体类,它负责加载和显示图像。`ProxyImage` 是一个代理类,它也实现了 `Image` 接口,并在需要时创建实际的 `RealImage` 对象,以确保对其的访问受到控制。 在 `main()` 方法中,我们创建了一个 `ProxyImage` 对象,并将其传递给 `Image` 接口的引用。在第一次调用 `display()` 方法时,代理类创建了实际的 `RealImage` 对象,并调用其 `display()` 方法。在第二次调用 `display()` 方法时,代理类直接调用实际对象的 `display()` 方法,而不需要再创建它。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值