Context比static或全局变量更合适,因其避免状态干扰、支持单元测试隔离、职责清晰且符合单一职责原则;它通过显式传参封装共享状态,保障数据流可追踪、可维护、易扩展。

面向对象系统里没有真正的“全局变量”,但有更安全、更可控的替代方案——上下文对象(Context)。它不是把变量扔进全局命名空间,而是用一个专门的对象封装运行时所需共享的状态,并通过依赖注入或参数传递的方式,在需要的地方被使用。这种方式既避免了全局污染,又保证了数据流向清晰、可测试、易维护。
为什么 Context 比 static 或全局变量更合适
直接用 public static 字段或顶层类变量看似简单,但会带来几个实际问题:
- 多个实例间状态互相干扰(比如多用户并发时统计错乱)
- 单元测试困难——静态状态无法重置或隔离
- 职责不清:谁创建?谁修改?谁销毁?边界模糊
- 违反单一职责原则,让业务类承担状态管理负担
Context 的典型结构与用法
一个轻量级 Context 类通常只做三件事:持有数据、提供读写接口、不参与业务逻辑。
例如 Java 中定义一个 LearningContext:
public class LearningContext {private int totalAttempts = 0;
private int correctAnswers = 0;
private String currentStudentId;
public void recordAttempt() { totalAttempts++; }
public void recordCorrect() { correctAnswers++; }
public double getAccuracy() {
return totalAttempts == 0 ? 0.0 : (double) correctAnswers / totalAttempts;
}
// getter/setter 略
}
关键点在于:所有运算方法(addition、subtraction 等)都接收这个 Context 实例作为参数,而不是各自 new 一个 Scanner 或硬编码统计逻辑。
如何在方法链中自然传递 Context
Context 不靠“到处 new”或“static 引用”,而是顺着调用链层层传入:
- main() 创建 Context 实例
- main() 调用 menu(),同时把 Context 传过去
- menu() 根据用户选择调用 addition(context),subtraction(context) 等
- 每个运算方法内部调用 context.recordAttempt() 和 context.recordCorrect()
这样数据流是单向、显式、可追踪的。不需要 getter/setter 到处复制值,也不用担心某个方法意外清空或覆盖状态。
进阶:支持多用户或分场景隔离
如果系统要支持多个学生同时练习,Context 可以升级为工厂模式:
- 用 Map
按 studentId 管理独立上下文 - 每次进入题目前,根据当前用户取出专属 Context
- 每个学生的尝试次数、正确率完全隔离,互不影响
这种设计天然适配后续扩展,比如加入时间戳、题目难度权重、错题归档等,只需往 Context 里加字段和方法,不改动原有流程。










