结构型模式-代理模式

发布于:2025-06-12 ⋅ 阅读:(28) ⋅ 点赞:(0)

定义:

        代理模式(Proxy Pattern)是一个使用率非常高的模式,其定义如下: Provide a surrogate or placeholder for another object to control access to it.(为其他对象提供 一种代理以控制对这个对象的访问。)

代理模式通用类图

        代理设计模式的核心思想是间接访问和控制增强。通过引入代理对象,将客户端对目标对象的直接访问转变为间接访问,代理对象充当客户端和目标对象之间的中介。在代理对象中,可以灵活地添加各种控制逻辑和增强功能,而无需修改目标对象的代码,从而实现对目标对象访问的控制和功能扩展,同时也符合开闭原则,提高了系统的可维护性和可扩展性。

角色:

代理模式包含以下几个核心角色:

1、抽象主题(Subject)

        抽象主题定义了目标对象和代理对象的共同接口,它声明了客户端可以调用的方法。客户端通过抽象主题接口与代理对象或目标对象进行交互,确保客户端可以以一致的方式访问目标对象和代理对象。

2、目标对象(Real Subject)

        目标对象是实际执行操作的对象,它实现了抽象主题接口中定义的方法,完成具体的业务逻辑。目标对象是客户端真正想要访问的对象,但客户端不直接访问它,而是通过代理对象间接访问。

3、代理对象(Proxy)

        代理对象实现了抽象主题接口,并且持有一个目标对象的引用。代理对象在客户端调用其方法时,可以在调用目标对象方法之前或之后执行额外的操作,如进行权限检查、记录访问日志、缓存结果等。代理对象通过这种方式控制对目标对象的访问,并为目标对象增加额外的功能。​

代码示例:

        代理设计模式有多种实现方式,常见的有静态代理和动态代理。下面分别通过代码示例来介绍这两种实现方式。

(一)静态代理

        静态代理是在编译期就确定代理类的代码,代理类和目标类实现相同的接口,代理类中包含对目标类的引用。

        以网络请求为例,假设我们有一个NetworkRequest接口用于发起网络请求,RealNetworkRequest类是实际执行网络请求的目标对象,ProxyNetworkRequest是代理对象。

// 抽象主题:网络请求接口

public interface NetworkRequest {

    void sendRequest(String url);

}

// 目标对象:实际的网络请求类

public class RealNetworkRequest implements NetworkRequest {

    @Override

    public void sendRequest(String url) {

        System.out.println("正在向 " + url + " 发送网络请求");

    }

}

// 代理对象:网络请求代理类

public class ProxyNetworkRequest implements NetworkRequest {

    private RealNetworkRequest realNetworkRequest;



    public ProxyNetworkRequest(RealNetworkRequest realNetworkRequest) {

        this.realNetworkRequest = realNetworkRequest;

    }



    @Override

    public void sendRequest(String url) {

        // 调用目标对象方法前的操作:权限验证

        System.out.println("进行权限验证");

        realNetworkRequest.sendRequest(url);

        // 调用目标对象方法后的操作:记录日志

        System.out.println("记录网络请求日志");

    }

}

// 客户端代码

public class StaticProxyClient {

    public static void main(String[] args) {

        RealNetworkRequest realRequest = new RealNetworkRequest();

        ProxyNetworkRequest proxyRequest = new ProxyNetworkRequest(realRequest);

        proxyRequest.sendRequest("https://example.com");

    }

}

(二)动态代理

        动态代理是在运行时动态生成代理类的字节码,并加载到内存中。Java 中提供了java.lang.reflect.Proxy类和InvocationHandler接口来实现动态代理。

同样以网络请求为例,代码如下:

// 抽象主题:网络请求接口

public interface NetworkRequest {

    void sendRequest(String url);

}

// 目标对象:实际的网络请求类

public class RealNetworkRequest implements NetworkRequest {

    @Override

    public void sendRequest(String url) {

        System.out.println("正在向 " + url + " 发送网络请求");

    }

}

// 调用处理器:实现InvocationHandler接口

public class NetworkRequestInvocationHandler implements InvocationHandler {

    private Object target;



    public NetworkRequestInvocationHandler(Object target) {

        this.target = target;

    }



    @Override

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        // 调用目标对象方法前的操作:权限验证

        System.out.println("进行权限验证");

        Object result = method.invoke(target, args);

        // 调用目标对象方法后的操作:记录日志

        System.out.println("记录网络请求日志");

        return result;

    }

}

// 客户端代码

public class DynamicProxyClient {

    public static void main(String[] args) {

        RealNetworkRequest realRequest = new RealNetworkRequest();

        NetworkRequestInvocationHandler handler = new NetworkRequestInvocationHandler(realRequest);

        NetworkRequest proxy = (NetworkRequest) Proxy.newProxyInstance(

                realRequest.getClass().getClassLoader(),

                realRequest.getClass().getInterfaces(),

                handler

        );

        proxy.sendRequest("https://example.com");

    }

}

优点 :

1、功能扩展灵活:通过代理对象可以在不修改目标对象代码的情况下,方便地为目标对象增加各种功能,如权限验证、日志记录、缓存处理等,符合开闭原则。

2、解耦客户端与目标对象:客户端只与代理对象交互,不直接依赖目标对象,降低了客户端与目标对象之间的耦合度,提高了系统的可维护性和可扩展性。

3、控制访问:代理对象可以对目标对象的访问进行控制,确保只有符合条件的访问才能到达目标对象,增强了系统的安全性和稳定性。


缺点:

1、增加系统复杂度:代理设计模式引入了代理对象,增加了系统的类数量和代码复杂度,尤其是在动态代理中,涉及到反射机制,使代码的理解和调试变得更加困难。

2、性能开销:代理对象在调用目标对象方法时,需要进行额外的方法调用和逻辑处理,会带来一定的性能开销。在一些对性能要求极高的场景中,需要谨慎使用代理设计模式。


使用场景: 

(一)远程代理

        当目标对象位于远程服务器上时,通过代理对象可以隐藏网络通信的细节,客户端只需与本地的代理对象交互,就像访问本地对象一样。例如,RPC(远程过程调用)框架中就广泛使用了远程代理。

(二)虚拟代理

        对于创建开销较大的对象,如加载大尺寸图片、读取大型文件等,可以使用虚拟代理在需要时才创建目标对象,减少系统资源的浪费。在图片加载场景中,先显示一个占位图(代理对象),当真正需要显示图片时再加载实际的图片(目标对象)。

(三)保护代理

        保护代理用于控制对目标对象的访问权限,在代理对象中进行权限验证、身份认证等操作。例如,在企业管理系统中,不同角色的用户对某些功能的访问权限不同,可以通过保护代理来实现权限控制。

(四)缓存代理

        代理对象可以缓存目标对象的操作结果,当客户端再次请求相同操作时,直接返回缓存结果,提高系统的响应速度。在 Web 开发中,对于一些不经常变化的数据查询结果,可以使用缓存代理进行缓存。

        代理设计模式通过引入代理对象,实现了对目标对象访问的控制和功能扩展,为软件开发提供了一种灵活、强大的解决方案。无论是静态代理还是动态代理,都有其适用的场景和特点。在实际开发中,当遇到需要控制对象访问、扩展对象功能、隐藏对象细节等需求时,代理设计模式是一个不错的选择。但同时也要注意其带来的系统复杂度增加和性能开销问题,合理运用该模式,让代码更加优雅和高效。


网站公告

今日签到

点亮在社区的每一天
去签到