20.1 Proxy 模式

Proxy 是“代理人”的意思。指的是代替别人工作的人。

但是代理人毕竟不是本人,代理人解决不了的事情,还是要交给本人处理。

在 OOP 中,“本人”和 “代理人”都是对象。如果“本人”太忙了,有些工作无法亲自完成,就得交给“代理人”来完成

20.2 示例程序

类名 说明
Printer 表示带名字的打印机的类(本人)
Prinitable Printer 和 PrinterProxy 共同的接口
PrinterProxy 表示带名字的打印机的类(代理人)
Main 测试程序行为的类

Printer

  1. package Proxy;
  2. /**
  3. * @Author Gorit
  4. * @Date 2021/11/27
  5. * 表示 ”本人“ 的类
  6. **/
  7. public class Printer implements Printerable {
  8. private String name;
  9. /**
  10. * 在构造函数中,我们让 “本人” 干一些重活
  11. */
  12. public Printer() {
  13. heavyJob("Printer 实例生成中");
  14. }
  15. public Printer(String name) {
  16. this.name = name;
  17. heavyJob("Printer 实例生成中 (" + name + ")");
  18. }
  19. public void setPrinterName(String name) {
  20. this.name = name;
  21. }
  22. public String getPrinterName() { // 获取打印机的名字
  23. return name;
  24. }
  25. public void print(String string) { // 显示带打印机名字的文字
  26. System.out.println("=== " + name + " ===");
  27. System.out.println(string);
  28. }
  29. private void heavyJob(String msg) { // 干 5 秒 重活的方法,用 ”.“ 显示进度
  30. System.out.print(msg);
  31. for (int i = 0; i < 5; i++) {
  32. try {
  33. Thread.sleep(1000);
  34. } catch (InterruptedException e) {
  35. e.printStackTrace();
  36. }
  37. System.out.print(".");
  38. }
  39. System.out.println("结束");
  40. }
  41. }

Printerable

  1. package Proxy;
  2. /**
  3. * @Author Gorit
  4. * @Date 2021/11/27
  5. * 使 Printer 类 和 Printerable 具备一致性
  6. **/
  7. public interface Printerable {
  8. public abstract void setPrinterName(String name); // 设置打印机名字
  9. public abstract String getPrinterName(); // 获取打印机名字
  10. public abstract void print(String string); // 显示文字(打印输出)
  11. }

PrinterProxy

  1. package Proxy;
  2. /**
  3. * @Author Gorit
  4. * @Date 2021/11/27
  5. * Proxy 模式的核心
  6. * “代理人”的 角色的类
  7. **/
  8. public class PrinterProxy implements Printerable{
  9. private String name; // 名字
  10. private Printer real; // 本人
  11. public PrinterProxy() {
  12. }
  13. public PrinterProxy(String name) {
  14. this.name = name;
  15. }
  16. public synchronized void setPrinterName (String name) { // 设置名字
  17. if (real != null) {
  18. real.setPrinterName(name); // 同时设置本人的名字
  19. }
  20. this.name = name;
  21. }
  22. public String getPrinterName() { // 获取名字
  23. return name;
  24. }
  25. public void print(String string) { // 本人会被 this 调用,只有执行了该方法,PrinterProxy 类才会生成 Printer 类的实例
  26. realize();
  27. real.print(string);
  28. }
  29. private void realize() { // 生成本人
  30. if (real == null) {
  31. real = new Printer(name);
  32. }
  33. }
  34. }

Main

  1. package Proxy;
  2. /**
  3. * @Author Gorit
  4. * @Date 2021/11/27
  5. **/
  6. public class Main {
  7. public static void main(String[] args) {
  8. Printerable p = new PrinterProxy("Alice");
  9. System.out.println("现在的名字是 " + p.getPrinterName() + "。");
  10. p.setPrinterName("Bob");
  11. System.out.println("现在的名字是 " + p.getPrinterName() + "。");
  12. p.print("Hello World");
  13. }
  14. }

image.png

20.3 Proxy 中登场的角色

一、Subject(主体)

Subject 角色定义了 Proxy 角色 和 RealSubject 角色 之间具有一致性的接口。

由于存在 Subject 角色,所以 Client 角色不必在意使用的究竟是 Proxy 角色 还是 RealSubject 角色

示例程序中由 Printable 接口扮演此角色。

二、Proxy(代理人)

Proxy 角色会尽量处理来自 Client 角色的请求。只有自己不能处理时。它才会把工作交给 RealSubject 角色。

Proxy 角色只有在必要时才会生成 RealSubject 角色。Proxy 角色实现了在 Subject 角色中定义的接口

示例程序由 PrinerProxy 角色担任此角色

三、RealSubject(实际的主体)

“本人”RealSubject 角色会在“代理人”Proxy 角色无法胜任工作时出场。

它与 Proxy 角色一样,也实现了 Subject 角色定义的接口

示例程序中由 Printer 角色扮演此角色

四、Client(请求者)

使用 Proxy 模式的角色。

Main 担任此角色

20.4 拓展

一、使用代理人提升处理速度

在大型系统中,应用启动的时间非常长,但是一些暂时用不到的也一起初始化了。那么应用程序初始化的时间会非常长。因此我们可以使用代理模式在需要使用某个功能时将其初始化即可。

二、各种 Proxy 模式

  • Vitual Proxy(虚拟代理)

Virtual Proxy 就是本章中学习的 Proxy 模式,只有正在需要实例时,才创建实例

  • Remote Proxy(远程代理)

Remote Proxy 可以让我们完全不必在意 RealSubject 角色是否在远程网络上,可以如同他自己身边一样(透明地)调用它的方法。 Java 的 RMI (远程方法调用)就相当于 Remote Proxy

  • Acess Proxy

Acess Proxy 用于调用 RealSubject 角色时的功能访问限制,这种代理只允许指定用户调用方法,而其他用户调用则会报错。(Java 权限管理,AOP 就做这个事情的)

20.5 相关设计模式

一、Adapter 模式

Adapter 模式适配具有不同接口的对象,以使他们可以一起工作。而 Proxy 模式中,Proxy 角色与 RealSubject 角色的接口是相同的(透明性)

二、Decorator 模式

Decorator 模式与 Proxy 模式在是实现上都很相似,不过它们使用目的不同

Decorator 模式的目的在于增加新的功能。而 Proxy 模式,与其新增功能相比,它更加注重通过设置代理人的方法来减轻本人的工作负担

胜利在望了,最后两篇设计模式了