ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

代理模式(Proxy Pattern)实战指南:基于 java-design-patterns 源码解析访问控制与懒加载

代理模式(Proxy Pattern)实战指南:基于 java-design-patterns 源码解析访问控制与懒加载 示例工程教程【免费下载链接】java-design-patternsDesign patterns implemented in Java项目地址https://gitcode.com/GitHub_Trending/ja/java-design-patterns点击查看免费下载代理模式Proxy Pattern又称 Surrogate是 Gang of Four 提出的结构型设计模式之一其核心是为另一个对象提供替身或占位符从而在不改动真实对象代码的前提下控制对它的访问。本指南以当前仓库 java-design-patterns 中的 proxy 模块原文档为 localization/es/proxy/README.md为主线结合模块源码与测试用例完整讲解代理模式的意图、类结构、可复现的代码示例以及远程代理、虚拟代理、保护代理三种典型变体的适用场景。读完本文你将能够在自己的 Java 项目中实现一个带访问控制、懒加载或日志增强的代理层并理解它与 Adapter、Decorator、Facade、Ambassador 等模式的边界。模式的意图为什么需要代理按照原文档的定义代理模式的**目的Propósito**是提供另一个对象的替代品sustituto或占位符marcador de posición以控制对该对象的访问。用一句简单的话概括就是用一个类来代表另一个类的功能客户端与真实对象之间多了一层可控的中介。维基百科对代理的经典描述原文档引用是代理在其最一般的形式上是一个充当某事物接口的类。代理是一个包装对象或代理对象由客户端调用它以访问幕后的真实服务对象。代理的用途可以仅仅是转发到真实对象也可以提供额外的逻辑——例如在真实对象上的操作非常消耗资源时提供缓存或在真实对象上的操作被调用之前检查前置条件。这恰好点出了代理模式的两大价值透明地转发以及在不修改真实对象代码的前提下附加横切逻辑。真实世界案例象牙塔的守门人原文档给出了一个生动的现实隐喻想象一座塔当地的巫师们前来学习咒语。象牙塔只能通过一个代理进入该代理确保只有前三位巫师能够入塔。在这里代理代表了塔的功能并为其附加了访问控制。类似的现实对应物还包括小区门卫访客到来时门卫先核验其凭证与权限再决定是否放行。无论场景如何本质都一样——对真实对象居民/塔的访问必须经过一个检查关卡门卫/代理。模式结构四个参与者的职责从 proxy/etc/proxy.urm.puml 的类图定义和 proxy/src/main/java/com/iluwatar/proxy 的源码可以看出本示例由四个参与者构成参与者本示例中的类职责抽象主题SubjectWizardTower定义真实对象与代理共同实现的业务接口真实主题RealSubjectIvoryTower真正执行业务逻辑的对象即“被代理的对象”代理ProxyWizardTowerProxy持有真实主题的引用在调用前后附加控制逻辑客户端ClientApp只面向抽象主题编程感知不到代理的存在类图中明确标示了三个关键关系WizardTowerProxy聚合--持有WizardTower类型的tower引用IvoryTower实现..|WizardTowerWizardTowerProxy同样实现WizardTower。正是因为代理与真实对象实现同一接口客户端才能无差别地调用二者。程序化示例完整可运行的代码以下代码均可在 proxy/src/main/java/com/iluwatar/proxy 中找到原文实现。第一步定义抽象主题接口WizardTower.java 定义了业务契约public interface WizardTower { void enter(Wizard wizard); }第二步实现真实主题 IvoryTowerIvoryTower.java 使用 Lombok 的Slf4j注解生成日志器真实对象本身不包含任何访问控制逻辑它只负责“放行并记录”Slf4j public class IvoryTower implements WizardTower { public void enter(Wizard wizard) { LOGGER.info({} enters the tower., wizard); } }第三步定义被传入的对象 WizardWizard.java 是一个不可变的简单数据类通过RequiredArgsConstructor自动生成以name为参数的构造器并重写toString()以输出巫师姓名RequiredArgsConstructor public class Wizard { private final String name; Override public String toString() { return name; } }第四步实现代理 WizardTowerProxyWizardTowerProxy.java 是本模式的核心。它在构造时接收一个WizardTower真实对象并在enter方法中附加访问控制只有前NUM_WIZARDS_ALLOWED常量值 3位巫师可以入塔其余被拒绝Slf4j public class WizardTowerProxy implements WizardTower { private static final int NUM_WIZARDS_ALLOWED 3; private int numWizards; private final WizardTower tower; public WizardTowerProxy(WizardTower tower) { this.tower tower; } Override public void enter(Wizard wizard) { if (numWizards NUM_WIZARDS_ALLOWED) { tower.enter(wizard); numWizards; } else { LOGGER.info({} is not allowed to enter!, wizard); } } }注意这里的关键设计代理与真实对象实现同一接口代理内部保存接口类型的tower引用而非具体类因此代理可以在不改动IvoryTower任何代码的情况下对任意实现WizardTower的对象施加控制这正是“开闭原则”的体现。第五步客户端调用场景App.java 的main方法演示了完整的入塔场景——客户端通过代理而非直接使用IvoryTower依次让五位巫师尝试入塔public static void main(String[] args) { var proxy new WizardTowerProxy(new IvoryTower()); proxy.enter(new Wizard(Red wizard)); proxy.enter(new Wizard(White wizard)); proxy.enter(new Wizard(Black wizard)); proxy.enter(new Wizard(Green wizard)); proxy.enter(new Wizard(Brown wizard)); }程序输出运行 App 后日志输出如下时间戳与日志器名按实际运行环境略有差异Red wizard enters the tower. White wizard enters the tower. Black wizard enters the tower. Green wizard is not allowed to enter! Brown wizard is not allowed to enter!前三位巫师顺利入塔第四、第五位被代理拦截——真实对象IvoryTower从未被修改但访问行为已被代理完全控制。源码级佐证测试如何验证代理行为仓库为代理模块提供了完整的单元测试可作为行为契约的权威证据WizardTowerProxyTest.java 验证代理的访问控制让 Gandalf、Dumbledore、Oz、Merlin 四位巫师依次入塔断言前三位产生enters the tower.日志Merlin 产生is not allowed to enter!日志且日志总数为 4。这直接印证了NUM_WIZARDS_ALLOWED 3的计数逻辑。IvoryTowerTest.java 验证真实对象不设防同样四位巫师直接调用IvoryTower.enter四人全部产生入塔日志——两相对照可以直观看出“限制”完全来自代理层。AppTest.java 验证入口程序可无异常执行。测试基础设施 InMemoryAppender.java 是一个基于 LogbackAppenderBase的内存日志收集器将日志事件存入LinkedList为上述断言提供支撑。适用场景何时使用代理模式原文档明确只要需要比简单指针更灵活、更复杂的对象引用代理模式就适用。典型场景包括远程代理Remote Proxy为位于不同地址空间的对象提供本地代表如 Java RMI。虚拟代理Virtual Proxy按需创建开销昂贵的对象如大图加载、复杂计算结果的延迟实例化。保护代理Protection Proxy控制对原始对象的访问当不同对象需要不同访问权限时尤其有用。此外代理模式通常还被用于控制对另一个对象的访问延迟初始化Lazy Initialization实现日志记录Logging简化网络连接统计对象引用次数优点与权衡优点受控访问代理可以在调用真实对象之前执行检查、日志或其他附加操作而无需侵入真实对象的代码。延迟初始化代理可将资源密集型对象的创建推迟到真正需要时改善启动性能与内存占用。远程透明代理封装网络通信细节让客户端像调用本地对象一样操作远程对象。权衡额外开销增加一层代理会引入额外的间接层可能带来微小的性能开销。复杂度上升系统中新增类会提高结构复杂度需要权衡是否确有引入代理的必要。与相关模式的边界Ambassador与代理相似同为客户端与真实服务之间的中介特别适用于远程通信场景并会附加访问控制与监控能力。AdapterAdapter 改变现有对象的接口接口转换而 Proxy 与真实对象保持同一接口接口不变只控制访问。Decorator两者都提供间接层但 Decorator 是动态地为对象添加职责增强功能Proxy 则是控制访问。FacadeFacade 为复杂子系统提供简化接口Proxy 则针对单个对象控制访问。现实世界中的代理应用从本仓库文档可以梳理出代理模式在业界与 JDK 中的常见落点均为原文档列举此处仅列名称便于本地检索Java 标准库的动态代理工具 java.lang.reflect.ProxyJDK 反射代理、Apache Commons Proxy 项目以及 Mockito、PowerMock、EasyMock 等 Mock 框架——它们正是利用代理机制为测试对象生成替身iOS 的 UIAppearance 也运用了类似思想。理解手写代理的实现原理是理解这些框架内部机制的基石。如何在本地运行本示例进入仓库根目录本模块位于proxy/其构建配置见 proxy/pom.xml。该模块的pom.xml声明了slf4j-api、logback-classic运行时依赖以及junit-jupiter-engine、mockito-core测试依赖并通过maven-assembly-plugin将主类配置为com.iluwatar.proxy.App便于打包运行。在仓库根目录执行测试./mvnw -pl proxy test需要本机已安装 JDK 与 Maven且具备网络以拉取依赖。执行示例入口./mvnw -pl proxy exec:java或在 IDE 中直接运行com.iluwatar.proxy.App即可看到前三位巫师入塔、后两位被拒绝的日志输出。小结代理模式通过一个“同接口的替身对象”在客户端与真实对象之间建立可控的访问通道。本文以 java-design-patterns 仓库的proxy模块为完整蓝本从接口、真实对象、代理到客户端调用给出了可直接运行的代码并用测试用例验证了行为契约。掌握代理模式后你可以将其用于权限控制、懒加载、日志审计、远程调用封装等场景同时也为理解 JDK 动态代理与 Mock 框架的底层机制打下基础。若需进一步了解模式间的组合使用可继续阅读仓库中的 Ambassador、Adapter 与 Decorator 模块文档。赞分享示例工程教程【免费下载链接】java-design-patternsDesign patterns implemented in Java项目地址https://gitcode.com/GitHub_Trending/ja/java-design-patterns点击查看免费下载相关推荐Amlogic S9xxx 电视盒子安装 Armbian 完整指南新手从 0 到 Linux 服务器附避坑命令Amlogic S9xxx 电视盒子安装 Armbian 完整指南新手从 0 到 Linux 服务器附避坑命令 抽屉里吃灰的电视盒子其实可以 7×24 小示例工程教程Go Patterns 代理模式Proxy Pattern实战用拦截与受控访问包装昂贵资源Go Patterns 代理模式Proxy Pattern实战用拦截与受控访问包装昂贵资源 代理模式Proxy Pattern是 Go Pattern示例工程教程文档Java 设计模式Acyclic Visitor无环访问者模式解析与源码实战 —— 基于 java-design-patterns 仓库 acyclic-visitor 模块Java 设计模式Acyclic Visitor无环访问者模式解析与源码实战 —— 基于 java design patterns 仓库 acyclic示例工程教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表