静态代理模式:代码世界的“替身演员”

news/2025/2/4 15:38:34/文章来源:https://www.cnblogs.com/ccdm/p/18698247

一、关于静态代理

1.1 简介

静态代理是代理模式的一种实现方式,其特点是代理类在编译时就已经确定,代理类的代码是在程序编译阶段生成的,而不是运行时动态生成。

在静态代理中,代理对象和真实对象都需要实现相同的接口。代理类会通过调用真实对象的方法来完成实际的业务操作。代理类和真实类的关系是在编译阶段就已确定,因此也被称为"静态"代理。

3c333c54-d42e-452c-948d-e1dabe314e12

代理模式(Proxy Pattern) 是一种结构型设计模式,其核心思想是通过代理对象来间接访问真实对象,从而实现对真实对象的控制和扩展。代理模式通常用于延迟加载、权限控制、日志记录、性能监控等场景。

1.2 发展

  • 起源:静态代理随着OOP和设计模式的兴起而出现,用于解决功能扩展和访问控制问题。
  • 成熟:在1990s-2000s期间,静态代理被广泛应用于权限控制、日志记录等场景。
  • 挑战:随着系统复杂度增加,静态代理的局限性(如代码冗余和灵活性不足)逐渐显现。
  • 演进:动态代理技术的出现弥补了静态代理的不足,成为更主流的代理实现方式。

1.3 特点

优点

  1. 职责清晰:代理类负责控制访问,目标类专注于业务逻辑。
  2. 扩展性:可以在不修改目标类的情况下增强功能,如日志记录、权限检查等。
  3. 安全性:通过代理类限制对目标类的直接访问。

缺点

  1. 代码冗余:每个目标类都需要一个对应的代理类,增加代码量。
  2. 灵活性不足:代理类与目标类紧密耦合,难以应对复杂需求。

我们想要静态代理的好处,又不想要静态代理的缺点,所以 , 就有了动态代理(后续分享) !

1.4 核心组成

  1. 目标类(Real Subject) :实际执行业务逻辑的类。
  2. 代理类(Proxy) :实现与目标类相同的接口,并持有目标类的引用,控制对目标类的访问。
  3. 接口(Subject) :定义目标类和代理类的共同行为。

1.5 应用场景

  • 需要对目标对象的功能进行增强(如日志记录、权限检查、性能监控等)。
  • 目标对象的创建和初始化成本较高,可以通过代理延迟加载。
  • 需要对目标对象的访问进行控制(如权限验证)。

二、实现步骤

  1. 定义一个接口,声明目标类和代理类的共同方法。
  2. 创建目标类,实现接口并完成核心业务逻辑。
  3. 创建代理类,实现相同的接口,并在方法调用前后添加额外逻辑。
  4. 客户端通过代理类访问目标类。

三、实现示例

示例1—权限检查

package org.example;public class StaticProxyDemo {// 1. 定义接口public interface UserService {void addUser(String name);}// 2. 实现目标类(实际执行业务逻辑)public static class UserServiceImpl implements UserService {@Overridepublic void addUser(String name) {System.out.println("添加用户: " + name);}}// 3. 创建代理类public static class UserServiceProxy implements UserService{// 持有目标对象的引用private UserService userService;public UserServiceProxy(UserService userService){this.userService=userService;}@Overridepublic void addUser(String name) {System.out.println("前置操作:权限检查");// 调用目标对象的方法userService.addUser(name);System.out.println("后置操作:日志记录");}}// 4. 使用代理类public static class Main{public static void main(String[] args) {// 创建目标对象UserServiceImpl userService = new UserServiceImpl();// 创建代理对象,并传入目标对象UserServiceProxy proxy  = new UserServiceProxy(userService);// 通过代理对象调用方法proxy.addUser("Mike");}}}

代理类代码解释:

  1. private UserService userService;
    这行代码定义了一个私有变量 userService​,其类型是 UserService​ 接口。这个变量的作用是保存对实际执行业务逻辑的对象(也就是被代理对象)的引用。通过这种方式,代理类 UserServiceProxy​ 可以在不改变原有功能的情况下,向原有的方法调用添加额外的行为(如前置操作和后置操作)。
  2. public UserServiceProxy(UserService userService)
    这是一个构造函数,它接受一个 UserService​ 类型的参数,并将其赋值给实例变量 userService​。这意味着当你创建 UserServiceProxy​ 的实例时,你需要传递一个实现了 UserService​ 接口的具体类的实例(即目标对象)。这样做使得 UserServiceProxy​ 能够在其内部使用该目标对象的方法,同时还可以在调用前后插入额外的操作。

输出

前置操作:权限检查
添加用户: Mike
后置操作:日志记录

image

示例2—日志功能

在增删改业务中增加日志功能

  1. 创建一个抽象角色,比如我们平时做的用户业务,抽象起来就是增删改查!

    // 抽象角色:增删改查业务
    public interface UserService {  void add();  void delete();  void update();  void query();
    }
    
  2. 我们需要一个真实对象来完成这些增删改查操作

    // 真实对象,完成增删改查操作的人
    public class UserServiceImpl implements UserService {  public void add() {  System.out.println("增加了一个用户");  }  public void delete() {  System.out.println("删除了一个用户");  }  public void update() {  System.out.println("更新了一个用户");  }  public void query() {  System.out.println("查询了一个用户");  }
    }
    
  3. 需求来了,现在我们需要增加一个日志功能,怎么实现!

    • 思路1 :在实现类上增加代码 【麻烦!】
    • 思路2:使用代理来做,能够不改变原来的业务情况下,实现此功能就是最好的了!
  4. 设置一个代理类来处理日志! 代理角色

    // 代理角色,在这里面增加日志的实现
    public class UserServiceProxy implements UserService {  private UserServiceImpl userService;  public void setUserService(UserServiceImpl userService) {  this.userService = userService;  }  public void add() {  log("add");  userService.add();  }  public void delete() {  log("delete");  userService.delete();  }  public void update() {  log("update");  userService.update();  }  public void query() {  log("query");  userService.query();  }  public void log(String msg){  System.out.println("执行了"+msg+"方法");  }
    }
    
  5. 测试访问类:

    public class Client {  public static void main(String[] args) {  //真实业务  UserServiceImpl userService = new UserServiceImpl();  //代理类  UserServiceProxy proxy = new UserServiceProxy();  //使用代理类实现日志功能!  proxy.setUserService(userService);  proxy.add();  }
    }
    

OK,到了现在代理模式大家应该都没有什么问题了,重点大家需要理解其中的思想;(在不改变原来的代码的情况下,实现了对原有功能的增强,这是Spring AOP中最核心的思想)

image

image

image

静态代理模式以简洁的方式架起了代码复用与功能扩展的桥梁,通过代理对象的“中间层”巧妙实现核心逻辑与附加功能的解耦。虽然其需要手动编写代理类的特性在接口频繁变动时略显笨拙,但在早期设计明确、功能需求稳定的场景中,它依然是轻量级增强代码灵活性的优选方案。

理解静态代理不仅能帮助我们掌握代理模式的核心思想,更是迈向动态代理、AOP等高级技术的重要基石。未来面对复杂场景时,不妨结合其他设计模式,让静态代理在架构设计中绽放更多可能。—— 用模式解决痛点,才是设计的真谛。

如果本文对你有帮助,欢迎点赞收藏!

📢 你的每一次互动,都是我持续创作的动力!

点击关注收藏

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/878590.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一个 .NET 开源、免费、功能强大的Windows应用卸载神器

前言 今天大姚给大家分享一个基于 .NET 开源(Apache License)、免费、功能强大的Windows应用卸载神器:Bulk Crap Uninstaller。 项目介绍 Bulk Crap Uninstaller 是一款基于 .NET 开源(Apache License)、免费、功能强大的Windows应用卸载工具,旨在帮助用户快速且有效地移…

强化学习驱动的自适应模型选择与融合用于监督学习

图片来源:Unsplash 上的 Agence Olloweb引言 机器学习模型的选择一直是一个挑战。无论是预测股票价格、诊断疾病,还是优化营销活动,问题始终是:哪个模型最适合我的数据? 传统上,我们依赖交叉验证来测试多个模型——XGBoost、LGBM、随机森林等——然后根据验证性能选择最佳…

Python 与 PostgreSQL 集成:深入 psycopg2 的应用与实践

title: Python 与 PostgreSQL 集成:深入 psycopg2 的应用与实践 date: 2025/2/4 updated: 2025/2/4 author: cmdragon excerpt: PostgreSQL 作为开源关系型数据库的佼佼者,因其强大的功能与性能被广泛应用于各种项目中。而 Python 则因其简洁易用的语法、丰富的库和强大的数…

Gitea Enterprise 23.0.0 (Linux, macOS, Windows) - 本地部署的企业级 Gti 服务

Gitea Enterprise 23.0.0 (Linux, macOS, Windows) - 本地部署的企业级 Gti 服务Gitea Enterprise 23.0.0 (Linux, macOS, Windows) - 本地部署的企业级 Gti 服务 The Premier Enterprise Solution for Self-Hosted Git Service 请访问原文链接:https://sysin.org/blog/gitea/…

【跟着阿舜学音乐-笔记】2.4电鼓及其他打击乐器

2.4电鼓及其他打击乐器 滚镲:使用滚奏的方式打击吊镲(由弱到强不断打击在自然地由强到弱) 2.4.1电鼓 电鼓分为两种来源,一种为合成器合成,另一种则是由架子鼓发出后进行电声的处理。 电鼓的军鼓会稍显薄弱,有时由采取再垫一轨的方式。此外,电鼓的踩镲在一些风格曲目中打…

[Nuxt] Rendering mode

A Nuxt app can be rendered in various modes. The default standard mode is simply called SSR. Specifically, it means Server-Side Rendering on request. “on request” means whenever the user clicks on an external link or enters a URL in the address bar to ac…

ASP.NET Core 中,认证(Authentication)和授权(Authorization)

在 ASP.NET Core 中,认证(Authentication)和授权(Authorization)是两个非常重要的概念。它们确保用户能够安全地访问应用程序,并且在访问过程中能按其权限被正确地控制。接下来,我将详细解释这两个概念,并且如何在 ASP.NET Core 中实现它们。 1. 认证(Authentication)…

ASP.NET Core 中,Cookie 认证在集群环境下的应用

在 ASP.NET Core 中,Cookie 认证在集群环境下的应用通常会遇到一些挑战。主要的问题是 Cookie 存储在客户端的浏览器中,而认证信息(比如 Session 或身份令牌)通常是保存在 Cookie 中,多个应用实例需要共享这些 Cookie 信息,以便用户在集群中各个实例间无缝切换。 1. 集群…

ASP.NET Core 中使用 Cookie 身份验证

在 ASP.NET Core 中使用 Cookie 身份验证,通常是为了实现用户的登录和授权。以下是配置 Cookie 身份验证的步骤。 1. 安装必要的 NuGet 包 首先,确保项目中包含 Microsoft.AspNetCore.Authentication.Cookies 包。你可以通过 NuGet 包管理器或命令行安装它: dotnet add pack…

GDB调试(一)

GDB调试 GDB简介 GDB的功能 GDB(GNU Debugger)是用于调试 C、C++ 等语言的强大工具。它允许开发者执行以下操作:启动程序并按照预期条件暂停(如断点处)。 检查程序中的变量和内存状态。 单步执行代码,观察每一步的变化。 修改运行中的变量值以测试不同的假设。 调试程序崩…

Nginx 粘性会话配置与实现详解

**Nginx 粘性会话(Sticky Session)**是指将同一个客户端的请求始终路由到相同的后端服务器,确保该客户端的多个请求在同一个会话期间都由同一台服务器处理。粘性会话通常在负载均衡环境中使用,特别是当应用程序依赖于在同一会话中保持用户状态(例如购物车、登录会话等)时…

ASP.NET Core 中,操作过滤器(Action Filters)

在ASP.NET Core 中,操作过滤器(Action Filters)用于在控制器的操作方法执行之前或之后执行自定义逻辑。操作过滤器主要用于在请求到达控制器方法之前进行处理(例如:验证请求参数、设置数据)、在操作执行后处理响应(例如:记录日志、修改响应结果)等。 操作过滤器的工作…