十二、结构型(署理模式)

[复制链接]
发表于 2026-1-6 13:13:51 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
署理模式(Proxy Pattern)

概念
署理模式(Proxy Pattern)是一种结构型操持模式,署理对象在不改变目的对象功能的条件下,通过控制对目的对象的访问,来实现耽误加载、权限控制、日志日志纪录等功能。署理模式可以通过提供一个中介对象,来控制客户端和实际目的对象之间的交互。

应用场景

  • 长途署理(Remote Proxy):为位于差别地点空间的对象提供署理,办理长途调用题目。典范的例子是RMI(Remote Method Invocation),通过署理对象举行长途方法调用。
  • 假造署理(Virtual Proxy):为某些须要较高开销的对象提供署理,耽误其加载和创建。好比,大型图片或文档的加载可以通过假造署理来举行,只有认真正须要时才创建实际对象。
  • 掩护署理(Protection Proxy):用于控制对对象的访问权限。署理对象查抄调用者是否具有访问权限,只有在权限答应时,才华访问目的对象。
  • 智能引用署理(Smart Reference Proxy):在访问对象时参加一些附加操纵,如统计实际对象的引用次数、纪录日志日志、查抄锁等。
  • 缓存署理(Caching Proxy):署理可以缓存某些盘算结果或操纵结果,使得后续的雷同哀求不须要重复盘算,提拔体系性能。

留意点

  • 署理类和实际类必须实现雷同的接口:署理类的操持应与目的类保持划一,使得客户端在利用署理类时与利用实际类没有差别。
  • 性能开销:只管署理模式可以增长功能,但也大概增长体系开销,尤其是长途署理涉及到网络传输时。
  • 恰当复杂的控制场景:署理模式尤其恰当在须要控制访问、管理复杂操纵、或添加额外处理处罚逻辑的场景中利用。

焦点要素

  • Subject(抽象主题脚色):界说署理类和目的类的共同接口,使得署理类和目的类可以被客户端通过雷同的方式调用。
  • RealSubject(真实主题脚色):界说目的对象,实现真实的业务逻辑。
  • Proxy(署理脚色):负责控制对真实主题对象的访问,通常会引用一个真实主题对象,并通过实现抽象主题接口来署理其操纵。

Java代码完备示例
代码示例:静态署理
  1. // 抽象接口,定义真实主题和代理共同的行为
  2. interface Subject {
  3.     void request();
  4. }
  5. // 真实主题,实现实际的业务逻辑
  6. class RealSubject implements Subject {
  7.     @Override
  8.     public void request() {
  9.         System.out.println("真实主题执行请求");
  10.     }
  11. }
  12. // 代理类,控制对真实主题的访问
  13. class Proxy implements Subject {
  14.     private RealSubject realSubject;
  15.     @Override
  16.     public void request() {
  17.         // 代理可以在调用真实对象之前执行一些额外操作
  18.         if (realSubject == null) {
  19.             realSubject = new RealSubject();
  20.         }
  21.         System.out.println("代理:在调用真实对象前的额外操作");
  22.         realSubject.request();
  23.         System.out.println("代理:在调用真实对象后的额外操作");
  24.     }
  25. }
  26. // 客户端
  27. public class Client {
  28.     public static void main(String[] args) {
  29.         Subject proxy = new Proxy();
  30.         proxy.request();
  31.     }
  32. }
复制代码
输出结果:
  1. 代理:在调用真实对象前的额外操作
  2. 真实主题执行请求
  3. 代理:在调用真实对象后的额外操作
复制代码

各种变形用法完备示例

  • 假造署理(Virtual Proxy)
    假造署理的重要目的是推迟大开销对象的创建,直到须要利用时才创建。典范例子是耽误加载大型图片或文档。
    代码示例:
    1. interface Image {
    2.     void display();
    3. }
    4. // 真实的图像类,实际加载图片
    5. class RealImage implements Image {
    6.     private String fileName;
    7.     public RealImage(String fileName) {
    8.         this.fileName = fileName;
    9.         loadFromDisk();
    10.     }
    11.     private void loadFromDisk() {
    12.         System.out.println("加载图片: " + fileName);
    13.     }
    14.     @Override
    15.     public void display() {
    16.         System.out.println("显示图片: " + fileName);
    17.     }
    18. }
    19. // 虚拟代理类
    20. class ProxyImage implements Image {
    21.     private RealImage realImage;
    22.     private String fileName;
    23.     public ProxyImage(String fileName) {
    24.         this.fileName = fileName;
    25.     }
    26.     @Override
    27.     public void display() {
    28.         if (realImage == null) {
    29.             realImage = new RealImage(fileName);
    30.         }
    31.         realImage.display();
    32.     }
    33. }
    34. // 客户端
    35. public class VirtualProxyClient {
    36.     public static void main(String[] args) {
    37.         Image image = new ProxyImage("test.jpg");
    38.         // 图片首次显示时加载
    39.         image.display();
    40.         System.out.println("");
    41.         // 第二次调用时不需要加载
    42.         image.display();
    43.     }
    44. }
    复制代码
    输出结果:
    1. 加载图片: test.jpg
    2. 显示图片: test.jpg
    3. 显示图片: test.jpg
    复制代码
  • 动态署理(Dynamic Proxy)
    动态署理是在运行时创建署理类,而不是在编译时创建。在Java中,可以利用java.lang.reflect.Proxy类来实现动态署理,署理类可以动态署理接口界说的全部方法。
    代码示例:
    1. import java.lang.reflect.InvocationHandler;
    2. import java.lang.reflect.Method;
    3. import java.lang.reflect.Proxy;
    4. // 定义抽象接口
    5. interface Service {
    6.     void operation();
    7. }
    8. // 实现接口的真实类
    9. class RealService implements Service {
    10.     @Override
    11.     public void operation() {
    12.         System.out.println("执行实际操作");
    13.     }
    14. }
    15. // 动态代理处理器
    16. class DynamicProxyHandler implements InvocationHandler {
    17.     private Object target;
    18.     public DynamicProxyHandler(Object target) {
    19.         this.target = target;
    20.     }
    21.     @Override
    22.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    23.         System.out.println("动态代理:在方法执行前");
    24.         Object result = method.invoke(target, args);
    25.         System.out.println("动态代理:在方法执行后");
    26.         return result;
    27.     }
    28. }
    29. // 客户端
    30. public class DynamicProxyClient {
    31.     public static void main(String[] args) {
    32.         RealService realService = new RealService();
    33.         Service proxyInstance = (Service) Proxy.newProxyInstance(
    34.             realService.getClass().getClassLoader(),
    35.             realService.getClass().getInterfaces(),
    36.             new DynamicProxyHandler(realService)
    37.         );
    38.         proxyInstance.operation();
    39.     }
    40. }
    复制代码
    输出结果:
    1. 动态代理:在方法执行前
    2. 执行实际操作
    3. 动态代理:在方法执行后
    复制代码
  • 掩护署理(Protection Proxy)
    掩护署理用于控制访问权限,可以通过署理来查抄调用者是否具备权限,只有在通过查抄时,才华调用目的对象的方法。
    代码示例:
    1. interface BankAccount {
    2.     void deposit(double amount);
    3.     void withdraw(double amount);
    4. }
    5. class RealBankAccount implements BankAccount {
    6.     private double balance;
    7.     public RealBankAccount(double balance) {
    8.         this.balance = balance;
    9.     }
    10.     @Override
    11.     public void deposit(double amount) {
    12.         balance += amount;
    13.         System.out.println("存款成功,当前余额: " + balance);
    14.     }
    15.     @Override
    16.     public void withdraw(double amount) {
    17.         if (balance >= amount) {
    18.             balance -= amount;
    19.             System.out.println("取款成功,当前余额: " + balance);
    20.         } else {
    21.             System.out.println("余额不足,取款失败");
    22.         }
    23.     }
    24. }
    25. // 保护代理类
    26. class ProtectionProxy implements BankAccount {
    27.     private RealBankAccount realBankAccount;
    28.     private String userRole;
    29.     public ProtectionProxy(String userRole, double initialBalance) {
    30.         this.userRole = userRole;
    31.         realBankAccount = new RealBankAccount(initialBalance);
    32.     }
    33.     @Override
    34.     public void deposit(double amount) {
    35.         realBankAccount.deposit(amount);
    36.     }
    37.     @Override
    38.     public void withdraw(double amount) {
    39.         if ("ADMIN".equals(userRole)) {
    40.             realBankAccount.withdraw(amount);
    41.         } else {
    42.             System.out.println("无权限取款");
    43.         }
    44.     }
    45. }
    46. // 客户端
    47. public class ProtectionProxyClient {
    48.     public static void main(String[] args) {
    49.         BankAccount adminAccount = new ProtectionProxy("ADMIN", 1000);
    50.         adminAccount.withdraw(500);
    51.         BankAccount userAccount = new ProtectionProxy("USER", 1000);
    52.         userAccount.withdraw(500);
    53.     }
    54. }
    复制代码
    输出结果:
    1. 取款成功,当前余额: 500.0
    2. 无权限取款
    复制代码

总结
署理模式通过引入署理类为目的对象提供额外的功能或控制。它实用于耽误加载、权限控制、日志日志纪录、长途调用等场景。署理模式可以分为静态署理和动态署理,而且具有多种变体,如假造署理、掩护署理、长途署理等。
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表