设计模式之上下文对象设计模式

目录

一、模式介绍

二、架构设计

三、Demo 示例

四、总结


一、模式介绍

上下文对象(Context Object)模式 最早由《Core J2EE Patterns》第二版提出,其核心目标是在多层或多组件间共享与当前作用域(如一次请求、一次会话、一次业务流程)相关的所有状态和服务,消除各组件对底层环境细节(如协议、线程、本地存储等)的直接依赖,从而提高系统的可复用性、可维护性和可测试性。Context Object 封装了与某个 Scope 相关的数据与行为,使各层或模块只需依赖该 Context,即可获得所需服务或状态,而无需显式传递大量参数或直接引用环境 API。

使用场景与历史背景

  • 在传统多层应用中,每一层如果要访问共享信息(如用户凭证、事务、配置参数),通常需要将其作为参数显式传递,导致方法签名臃肿、可读性差、易出错。

  • 随着 J2EE 应用复杂度提升,设计者发现将环境细节直接嵌入业务逻辑耦合度过高,维护成本激增。

  • 《Core J2EE Patterns》第二版总结了当时业界实践,将这种“共享环境数据”抽象为 Context Object 模式,对应 ApplicationContext/ServletContext、Hibernate SessionContext 等典型用法。

解决问题

  • 解耦:业务组件不必直接依赖环境(HTTP、JNDI、线程等)接口,一律通过 Context 获取所需信息或服务。

  • 集中管理:所有上下文相关的信息集中维护,便于调试、监控及扩展。

  • 生命周期一致性:Context 在作用域开始时创建,结束时统一销毁,资源释放更可控。

典型实现:

  • Apache Spark – SparkContext / SQLContext / StreamingContext

    聚合集群配置、调度、序列化、监控接口,并暴露 RDD/DataFrame/流计算等 API。

  • Flink – StreamExecutionEnvironment / ExecutionEnvironment

    封装执行引擎配置、并行度、checkpoint、状态后端等,用于构建批/流作业。


二、架构设计

以下为 Context Object 模式的标准 UML 类图:

主要组件说明

  • Context(接口):定义获取与存放上下文数据的方法。

  • ConcreteContext(实现类):内部维护一张属性映射,负责实际存取。

  • ContextFactory(工厂类):(可选)根据环境创建对应的 Context 实例。

  • Client:业务组件,通过构造器或工厂获取 Context 实例,并向其读写数据或调用存入的服务。


三、Demo 示例

问题场景:在一个 Web 应用或微服务中,常常需要在多个业务层(如控制层、服务层、数据访问层)之间传递用户会话信息、跟踪操作日志对象以及可复用的工具服务实例。直接在每个方法签名中传递这些参数,不仅会导致参数列表臃肿,还容易遗漏,增加维护成本。

解决方案:使用上下文对象模式,将所有需跨层共享的数据与服务封装到一个 Context 对象中,由各层直接从 Context 中获取,而不必在方法之间显式传递这些参数。

// 1. 定义 Context 接口,提供读写属性和服务获取功能
public interface RequestContext {<T> T get(String key, Class<T> type);void set(String key, Object value);
}
​
// 2. Context 实现,内部维护属性映射
public class RequestContextImpl implements RequestContext {private final Map<String, Object> data = new HashMap<>();
​@Overridepublic <T> T get(String key, Class<T> type) {return type.cast(data.get(key));}
​@Overridepublic void set(String key, Object value) {data.put(key, value);}
}
​
// 3. Context 工厂,初始化必要属性
public class RequestContextFactory {public static RequestContext create(String userId) {RequestContext ctx = new RequestContextImpl();// 初始化用户信息和日志追踪器ctx.set("userId", userId);ctx.set("traceId", UUID.randomUUID().toString());return ctx;}
}
​
// 4. 控制层:创建 Context 并启动业务流程
public class Controller {public void handleRequest(String userId) {RequestContext ctx = RequestContextFactory.create(userId);new BusinessService(ctx).process();}
}
​
// 5. 业务层:直接从 Context 获取 userId 和 TraceId,执行业务逻辑
public class BusinessService {private final RequestContext ctx;
​public BusinessService(RequestContext ctx) {this.ctx = ctx;}
​public void process() {String userId = ctx.get("userId", String.class);String traceId = ctx.get("traceId", String.class);// 输出日志时无需额外传参System.out.println("[" + traceId + "] Processing business logic for user " + userId);
​// 调用下一层服务new DataService(ctx).execute();}
}
​
// 6. 数据访问层:继续复用同一个 Context
public class DataService {private final RequestContext ctx;
​public DataService(RequestContext ctx) {this.ctx = ctx;}
​public void execute() {String traceId = ctx.get("traceId", String.class);// 使用 traceId 进行 SQL 日志关联System.out.println("[" + traceId + "] Executing SQL queries");}
}

说明

  • Controller 层只需创建并初始化一次 RequestContext,并传递给后续各层,不再维护多个参数。

  • 任何业务或数据访问类均可通过 ctx.get(...) 获取所需信息,简化方法签名。

  • 可扩展到添加更多上下文数据(如用户权限列表、国际化配置、第三方服务客户端等),只需在 Context 中新增属性,而无需改动各层接口。


四、总结

上下文对象模式 通过封装作用域相关的所有状态与服务,实现组件与环境的最大解耦,提升系统的灵活性和可维护性。

  • 价值

    • 模块化:各功能模块仅依赖 Context 接口,无须关注如何获取底层资源。

    • 扩展性:新增上下文数据或服务时,只需修改 Context 实现,无需改动业务层代码。

    • 测试友好:可为单元测试提供 Mock Context,对业务逻辑进行隔离测试。

  • 注意事项

    • 避免 Context 过于庞大,必要时可拆分为多个子 Context(如 ConfigContext、SecurityContext)。

    • 随着系统复杂度上升,建议引入成熟的 IoC/DI 容器(如 Spring ApplicationContext)来管理对象生命周期和依赖注入。

Context Object 模式是企业级应用架构中常见且行之有效的方案,既可手写实现,也可借助框架。它在《Core J2EE Patterns》一书中的提炼,为现代微服务与云原生开发中的“作用域数据共享”提供了理论基础与实践指导。

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

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

相关文章

@Linux服务器加域退域

文章目录 **一、加入Active Directory域****1. 准备工作****2. 配置步骤****步骤1&#xff1a;验证网络和DNS****步骤2&#xff1a;发现域****步骤3&#xff1a;加入域****步骤4&#xff1a;配置SSSD&#xff08;可选&#xff09;****步骤5&#xff1a;配置sudo权限&#xff08…

鸿蒙系统(HarmonyOS)4.2 设备上实现无线安装 APK 并调试

在鸿蒙系统&#xff08;HarmonyOS&#xff09;4.2 设备上实现无线安装 APK 并调试的步骤与 Android 类似&#xff0c;但需注意鸿蒙系统的特殊设置。以下是详细操作指南&#xff1a; 鸿蒙系统特殊准备 开启开发者选项&#xff1a; - 设置 > 关于手机 > 连续点击"H…

MyBatis时间戳查询实战指南

在 MyBatis 中通过时间戳&#xff08;Timestamp&#xff09;作为查询条件&#xff0c;需注意数据库时间类型与 Java 类型的映射。以下是具体实现方式&#xff1a; 一、Java 实体类与数据库字段映射 实体类定义 使用 java.sql.Timestamp 或 java.time.LocalDateTime&#xff08;…

【Verilog硬件语言学习笔记4】FPGA串口通信

串口通信是系统设计中比较基部分&#xff0c;其原理其实也很通俗易懂。单次建立通信会传输8个bit&#xff0c;其时序也很简单&#xff0c;这里就不再赘述了。其对应的实例代码如下所示&#xff1b; 首先是接受部分&#xff08;因为我的变量命名也很规范&#xff0c;通俗易懂&a…

Go 语言安装教程(Windows 系统)

2025年07月02日 准备工作 确认系统为 Windows 7 及以上版本&#xff08;推荐 Windows 10/11&#xff09;。64 位系统选择 amd64 版本安装包&#xff0c;32 位系统选择 386 版本。确保安装目录&#xff08;默认 C:\Program Files\Go\&#xff09;有至少 1GB 空间。 下载安装包…

接口测试之postman

一、Postman功能简介 3天精通Postman接口测试&#xff0c;全套项目实战教程&#xff01;&#xff01; Postman是由Postdot Technologies公司打造的一款功能强大的调试HTTP接口的工具。在做接口测试的时候&#xff0c;Postman相当于一个客户端&#xff0c;它可以模拟用户发起的各…

【记录】Ubuntu安装Mysql

本文记录Ubuntu系统下安装Mysql 1 查看系统信息 lsb_release -a 2 使用apt下载安装Mysql 1 打开终端,首先更新你的系统包索引,以确保所有包都是最新的 sudo apt update 2 安装mysql服务器 sudo apt install mysql-server (也可以选择对应的mysql-server 版本) 3 查看mysql状…

【深度学习:进阶篇】--4.1.循环神经网络(改进)

RNN存在的问题&#xff1a;梯度爆炸&#xff0c;长期依赖参数量过大等问题 目录 1.GRU(门控循环单元) 1.1.什么是GRU 1.2.直观理解 1.3.本质解决问题 2.LSTM(长短记忆网络) 2.1.作用 3.结构扩展与效率优化​ 1.GRU(门控循环单元) 2014年&#xff0c;出现的算法&#x…

中心化钱包安全方案

先来看独立的密钥安全技术 1 自建或单租户 CloudHSM 优点&#xff1a;密钥永不出硬件&#xff0c;无法导出&#xff0c;只能对外提供公钥。 交易时&#xff0c;外部应用把消息哈希传进去签名&#xff0c;再把签好名的结果拿出来用。 这种方式安全性拉满&#xff0c;但成本高、…

Android 实现底部弹窗

文章目录在 Android 中创建优雅的底部选项弹窗 (BottomSheetDialogFragment) &#x1f4f1;第一步&#xff1a;设计底部弹窗的布局 &#x1f3a8;第二步&#xff1a;创建 BottomSheetDialogFragment 类 ⚙️第三步&#xff1a;触发并显示底部弹窗 &#x1f680;在 Android 中创…

LAN8720 寄存器概览和STM32 HAL库读写测试

目录 寄存器0x00:Basic Control Register&#xff08;BCR&#xff09;0x01:Basic Status Register&#xff08;BSR&#xff09; 连接测试寄存器读写测试 补充 寄存器 // 0x00:Basic Control Register&#xff08;BCR&#xff09; BIT15:Soft Reset 写1复位&#xff0c;写1之…

渗透测试深度分析:空密码Administrator账户引发的安全风暴

渗透测试深度分析&#xff1a;空密码Administrator账户引发的安全风暴0x01 测试背景 在内网渗透测试中&#xff0c;对Windows主机 192.168.1.98 使用 enum4linux 进行枚举&#xff1a; enum4linux -u Administrator -p -a 192.168.1.98关键发现&#xff1a;Administrator账户空…

OpenCV CUDA模块设备层-----高效地计算两个 uint 类型值的带权重平均值

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 OpenCV 的 CUDA 模块&#xff08;cudev&#xff09; 中的一个设备端内联函数&#xff0c;用于高效地计算两个 uint 类型值的带权重平均值。 该函…

[学习记录]Unity毛发渲染[URP]-Shell基础版

毛发&#xff0c;无论是人类的头发、动物的皮毛&#xff0c;还是奇幻生物的绒毛&#xff0c;都是构成生命感和真实感不可或缺的元素。它对光线的独特散射、吸收和反射&#xff0c;赋予了物体柔软、蓬松、有生命力的质感。它不仅仅是让角色看起来更“毛茸茸”那么简单&#xff0…

数字孪生技术引领UI前端设计潮流:增强现实(AR)的集成应用

hello宝子们...我们是艾斯视觉擅长ui设计、前端开发、数字孪生、大数据、三维建模、三维动画10年经验!希望我的分享能帮助到您!如需帮助可以评论关注私信我们一起探讨!致敬感谢感恩!一、引言&#xff1a;AR 与数字孪生融合的设计革新浪潮在体验经济与技术融合的双重驱动下&…

碰一碰发视频源码搭建与定制化开发:支持OEM

在近场通信&#xff08;NFC&#xff09;技术与移动终端深度融合的背景下&#xff0c;“碰一碰发视频” 功能凭借便捷的交互体验&#xff0c;在商业推广、信息传递等场景中快速落地。不同于标准化解决方案的黑盒模式&#xff0c;基于源码的定制化开发能从底层优化传输效率、提升…

Ubuntu 24.04 安装配置 Redis 7.0 开机自启

下载源码 wget https://download.redis.io/releases/redis-7.0.12.tar.gz安装依赖 & 准备环境 sudo apt update && sudo apt upgrade -y sudo apt install -y build-essential tcl curl解压 tar xzf redis-7.0.12.tar.gz编译安装 cd redis-7.0.12 make -j$(nproc) …

【Linux 系统】基础IO——Linux中对文件的理解

13.基础IO(1) 文章目录13.基础IO(1)文件的基本概念&#xff1a;内容与属性文件的打开机制&#xff1a;fopen 和 open被打开的文件与磁盘文件的区别文件的内核数据结构文件与进程的交互方式标准输入/输出/错误与文件流系统调用与文件描述符文件打开模式&#xff08;r/w/a/a&…

Go调度器的抢占机制:从协作式到异步抢占的演进之路|Go语言进阶(7)

想象一下这样的场景&#xff1a;你在餐厅排队等位&#xff0c;前面有个人点了餐却一直霸占着座位玩手机&#xff0c;后面的人只能干等着。这就是Go早期版本面临的问题——一个goroutine如果不主动让出CPU&#xff0c;其他goroutine就只能饿着。 今天我们来聊聊Go调度器是如何解…

开源模型应用落地-让AI更懂你的每一次交互-Mem0集成Qdrant、Neo4j与Streamlit的创新实践(四)

一、前言 在人工智能迅速发展的今天,如何让AI系统更懂“你”?答案或许藏在个性化的记忆管理之中。Mem0作为一个开源的记忆管理系统,正致力于为AI赋予长期记忆与个性化服务能力。通过结合高性能向量数据库Qdrant、图数据库Neo4j的强大关系分析能力以及Streamlit的高效可视化交…