当前位置: 首页 > news >正文

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

目录

一、模式介绍

二、架构设计

三、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.dtcms.com/a/264330.html

相关文章:

  • 机器学习在智能金融风险评估中的应用:信用评分与欺诈检测
  • 电脑键盘不能打字了怎么解决 查看恢复方法
  • 无人机一机多控技术要点难点
  • Redis 概述及安装
  • 设计模式之组合模式
  • RabbitMQ:消息队列的轻量级王者
  • 系统安全之大模型案例分析
  • 用openCV实现基础的人脸检测与情绪识别
  • 磐维数据库panweidb3.1.0单节点多实例安装
  • 【Python】断言(assert)
  • 1.MySQL之如何定位慢查询
  • 隔离网络(JAVA)
  • 【前端】vue工程环境配置
  • linux 用户态|内核态打印函数调用进程的pid
  • OEM怎么掌握软件开发能力
  • Linux CentOS环境下Java连接MySQL数据库指南
  • Golang的代码结构设计原则与实践与模式应用
  • 解码知识整理,使您的研究更高效!
  • Java项目:基于SSM框架实现的中学教学管理系统【ssm+B/S架构+源码+数据库+毕业论文+开题报告】
  • [创业之路-458]:企业经营层 - 蓝海战略 - 重构价值曲线、整合产业要素、创造新需求
  • 软件产品使用说明编写需要注意的内容避坑指南
  • Day 3:Python模块化、异常处理与包管理实战案例
  • 【每天一个知识点】均值偏移(Mean-Shift)
  • 智能客服革新:元智启 AI 如何重塑企业服务体验
  • ctfshow web89-web98(php特性篇)
  • 2023年全国硕士研究生招生考试英语(一)试题总结
  • 【Python基础】13 知识拓展:CPU、GPU与NPU的区别和联系
  • SAP ABAP 中 AMDP 简介及实现方法
  • 【Linux】进程创建——fork()函数深度解析
  • Linux->进程控制(精讲)