参考文献

代理模式

  • 让你能够提供对象的替代品或其占位符. 代理控制着对于原对象的访问, 并允许在将请求提交给对象前后进行一些处理.

组件

  • 抽象主题(Subject): 定义了真实主题和代理主题之间的共同接口,客户端通过该接口访问真实主题.
  • 真实主题(Real Subject): 定义了真实对象的具体业务逻辑.代理对象通过调用真实主题来完成实际的操作.
  • 代理主题(Proxy Subject): 实现了抽象主题接口,并在其内部维护了一个引用,指向真实主题对象.代理主题负责控制对真实主题对象的访问,并且可以在真实主题的基础上增加额外的功能,如权限验证、缓存等.
  • 客户端(Client): 通过抽象主题接口与代理主题进行交互.客户端不需要知道真实主题的存在,只需要通过代理主题完成相应的操作.

实现方式

  • 定义抽象主题接口: 首先,需要定义一个抽象主题接口,该接口定义了真实主题和代理主题之间的共同方法.

    1
    2
    3
    4
    public interface FileServer {
    void uploadFile(String fileName);
    void downloadFile(String fileName);
    }
  • 实现真实主题类: 创建真实主题类,实现抽象主题接口,并实现具体的业务逻辑.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    public class RemoteFileServer implements FileServer {
    @Override
    public void uploadFile(String fileName) {
    System.out.println("正在上传文件: " + fileName);
    // 连接远程服务器,执行上传操作
    // ...
    System.out.println("上传完成");
    }

    @Override
    public void downloadFile(String fileName) {
    System.out.println("正在下载文件: " + fileName);
    // 连接远程服务器,执行下载操作
    // ...
    System.out.println("下载完成");
    }
    }
  • 创建代理主题类: 创建代理主题类,也实现抽象主题接口.在代理主题类中,维护一个对真实主题对象的引用,并且可以在方法调用前后进行额外的操作.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    public class FileServerProxy implements FileServer {
    private FileServer fileServer;

    public FileServerProxy() {
    this.fileServer = new RemoteFileServer();
    }

    @Override
    public void uploadFile(String fileName) {
    // 执行额外操作,如权限验证
    if (checkPermission()) {
    // 调用真实主题的方法
    fileServer.uploadFile(fileName);
    } else {
    System.out.println("无权限进行文件上传");
    }
    }

    @Override
    public void downloadFile(String fileName) {
    // 执行额外操作,如日志记录
    logDownload(fileName);
    // 调用真实主题的方法
    fileServer.downloadFile(fileName);
    }

    private boolean checkPermission() {
    // 检查用户权限逻辑
    // ...
    return true; // 假设所有用户都有上传权限
    }

    private void logDownload(String fileName) {
    // 记录下载日志逻辑
    // ...
    System.out.println("正在下载文件: " + fileName);
    }
    }
  • 客户端使用代理对象: 在客户端中,使用代理主题对象进行操作.客户端只需通过抽象主题接口与代理主题交互,无需直接与真实主题打交道.

    1
    2
    3
    4
    5
    6
    7
    public class Client {
    public static void main(String[] args) {
    FileServer fileServer = new FileServerProxy();
    fileServer.uploadFile("example.txt");
    fileServer.downloadFile("example.txt");
    }
    }

使用场景

  • 延迟初始化(虚拟代理): 当有一个重量级的服务对象,并且只有在需要时才希望进行初始化,可以使用代理模式来延迟初始化,减少系统资源的消耗.

  • 访问控制(保护代理): 当希望限制特定客户端对服务对象的访问权限时,可以使用代理模式来实现访问控制,只允许特定的客户端进行访问.

  • 本地执行远程服务(远程代理): 当服务对象位于远程服务器上时,可以使用代理模式在本地创建一个代理对象,通过网络与远程对象进行通信,实现本地调用远程服务.

  • 记录日志请求(日志记录代理): 当需要对对服务对象的请求进行日志记录时,可以使用代理模式来记录请求日志,方便后续的调试和问题排查.

  • 缓存请求结果(缓存代理): 当客户端请求的结果具有重复性,并且结果的计算成本较高时,可以使用代理模式来缓存请求结果,提高系统性能.

  • 智能引用: 当某个重量级对象没有客户端使用时,可以使用代理模式来立即销毁该对象,以节省资源.