1. 从“context-mode”说起:一个被低估的工程概念
第一次看到“context-mode”这个词,很多人会下意识地把它归到某个具体框架的配置项里,比如某个前端库的渲染模式、某个数据库的连接上下文、又或者是某个AI工具里的对话上下文开关。但如果你真的在工程一线待过几年,就会发现“context-mode”其实是一个横跨多个技术领域的通用设计思路——它描述的是系统在不同上下文环境下,如何切换自身的行为模式、资源分配策略和数据处理逻辑。
我最早接触这个概念是在做后端服务治理的时候。当时我们有一套API网关,需要同时服务Web端、移动端和第三方合作方。Web端希望拿到完整的JSON数据,移动端希望字段精简、响应快,第三方则要求特定的签名和限流策略。如果每个端都写一套独立的接口,维护成本会爆炸。后来我们引入了“context-mode”的思路:请求进来先识别上下文(来源、设备、认证级别、调用频率),然后动态切换到对应的处理模式。这套机制上线后,接口数量减少了60%,而各端的满意度反而提升了。
这就是“context-mode”的核心价值:用一套代码或一套系统,通过识别和切换上下文,来适配多种差异化的需求场景。它不是一个具体的库或框架,而是一种架构层面的设计哲学。无论你是在做前端状态管理、后端服务路由、数据库查询优化,还是AI应用的对话管理,只要面临“同一套逻辑要服务多种场景”的问题,context-mode都值得你认真考虑。
这篇文章适合谁看?如果你是有一定开发经验、正在为多端适配或多场景兼容头疼的工程师,那这篇内容会给你一套完整的落地思路。如果你刚入行,对“上下文”“模式切换”这些词还比较模糊,也没关系,我会用生活化的类比把原理讲清楚。全文会围绕context-mode的设计思路、核心实现、实操步骤和踩坑经验展开,尽量做到你看完就能在自己的项目里试起来。
2. 核心思路拆解:context-mode到底在解决什么问题
2.1 什么是“上下文”,为什么它值得单独抽一层
在软件系统里,“上下文”这个词被用得很多,但很多人对它的理解停留在“请求头里的User-Agent”或者“当前登录用户的信息”。这其实只是上下文的一部分。从工程角度看,一个完整的上下文至少包含四个维度:
- 环境维度:请求来源(Web、iOS、Android、小程序、第三方服务)、网络状况(4G、5G、WiFi)、设备能力(屏幕尺寸、内存、是否支持某些API)。
- 身份维度:用户角色(游客、普通用户、VIP、管理员)、认证方式(Token、Session、签名)、权限范围。
- 业务维度:当前所处的业务阶段(浏览、下单、支付、售后)、租户ID(多租户系统)、实验分组(A/B测试)。
- 运行时维度:当前系统的负载情况、数据库连接池状态、缓存命中率、限流阈值。
把这四个维度抽出来单独管理,好处非常明显。第一,决策逻辑集中化:所有“根据上下文做不同处理”的判断都收敛到一个地方,而不是散落在几十个if-else里。第二,可观测性提升:你可以清楚地知道当前系统处于哪种模式、为什么切换到了这个模式。第三,测试更容易:你可以模拟不同的上下文组合,验证系统行为是否符合预期。
我见过很多项目,上下文信息像毛细血管一样渗透在代码的各个角落。一个订单查询接口里,先判断用户是不是VIP,再判断请求来自哪个端,再判断当前是不是大促期间,最后才决定返回哪些字段。这种代码写起来快,但改起来要命。每次新增一个端或一种用户角色,都要把所有类似的接口翻一遍。context-mode的思路就是把这些判断抽出来,形成一个独立的“上下文解析层”和“模式决策层”。
2.2 context-mode的三种典型实现形态
根据我的经验,context-mode在不同系统里有三种常见的实现形态,各有优劣,适用于不同的场景。
第一种:策略模式+上下文对象。这是最经典的做法。定义一个Context类,封装所有上下文信息;定义一组Strategy接口,每个策略对应一种模式;再写一个ContextResolver,根据Context对象决定使用哪个Strategy。这种做法的优点是结构清晰、符合开闭原则,新增模式只需要加一个Strategy实现。缺点是类数量会膨胀,如果模式组合很多,策略类的维护成本不低。适合业务逻辑复杂、模式差异大的场景。
第二种:配置驱动+规则引擎。把模式切换的规则写成配置(JSON、YAML或DSL),运行时由规则引擎解析配置并执行对应逻辑。比如“如果来源是移动端且用户是VIP,则走精简模式并提升限流阈值”。这种做法的优点是规则可动态调整,不需要发版;缺点是规则复杂后难以调试,性能也有一定损耗。适合需要频繁调整策略、或者由运营人员配置规则的场景。
第三种:中间件/拦截器链。在请求进入业务逻辑之前,通过一系列中间件依次处理上下文信息,每个中间件负责一个维度的判断和模式标记。比如第一个中间件识别设备类型,第二个中间件解析用户身份,第三个中间件根据前两者的结果决定数据裁剪策略。这种做法的优点是灵活、可组合,每个中间件职责单一;缺点是链路长了之后排查问题比较麻烦,而且中间件之间的顺序依赖需要严格管理。适合请求处理管道已经比较成熟的系统。
这三种形态不是互斥的,实际项目中经常混用。比如用中间件做上下文采集,用策略模式做核心业务逻辑的模式切换,用配置驱动做限流和降级策略的动态调整。选择哪种,取决于你的团队规模、业务复杂度和运维能力。
2.3 为什么现在context-mode越来越重要
过去十年,软件系统的复杂度增长主要来自两个方向:终端多样化和场景细分化。十年前,一个Web应用可能只需要服务桌面浏览器;现在,同一个业务要同时服务Web、iOS、Android、小程序、智能音箱、车载系统,甚至第三方API调用方。每个终端的交互方式、数据需求、性能约束都不一样。如果不用context-mode的思路来管理这些差异,代码会迅速腐化。
另一个推动因素是AI应用的兴起。在大模型应用里,“上下文”有了新的含义:对话历史、用户画像、知识库检索结果、工具调用记录。一个AI助手需要根据当前对话的上下文,决定是直接回答、调用工具、还是转人工。这本质上也是context-mode:根据上下文切换回答模式。而且AI场景下的上下文更加动态、更加不确定,对模式切换的实时性和准确性要求更高。
还有一个容易被忽视的因素是成本。在云原生时代,计算资源、数据库连接、API调用次数都是要花钱的。通过context-mode,你可以让高成本的操作只在必要时执行。比如,只有VIP用户才走复杂的推荐算法,普通用户走缓存结果;只有移动端才做图片压缩,Web端返回原图。这种精细化的资源分配,在流量大的系统里能省下可观的成本。
3. 核心细节解析:从上下文采集到模式切换的完整链路
3.1 上下文采集:哪些信息值得收集,哪些是噪音
做context-mode的第一步是采集上下文。但采集不是越多越好,信息过载会导致决策逻辑复杂、性能下降。我的经验是遵循“三用原则”:用于路由、用于裁剪、用于限流。只有能直接影响这三个决策的信息才值得采集。
用于路由的信息包括:请求来源(通过User-Agent、Referer、自定义Header识别)、API版本号、租户ID、地理位置(粗粒度,如国家/地区级别)。这些信息决定了请求应该被分发到哪个处理管道。
用于裁剪的信息包括:设备类型和屏幕尺寸(决定返回字段的多少和图片的规格)、用户角色和权限(决定哪些数据可见)、语言和时区(决定内容的本地化形式)。这些信息决定了返回数据的形态。
用于限流的信息包括:用户ID或IP(用于计数)、认证级别(决定配额大小)、当前系统负载(决定是否触发降级)。这些信息决定了请求是否被允许以及以什么优先级处理。
采集方式上,我推荐显式传递+隐式补充相结合。显式传递是指客户端在请求头或参数里明确带上关键信息,比如X-Client-Type: mobile、X-Api-Version: 2。隐式补充是指服务端根据已有信息推断,比如根据User-Agent解析出设备类型,根据IP解析出大致地域。显式传递的优先级高于隐式补充,因为客户端自己最清楚自己的情况。
注意:不要过度依赖User-Agent做设备识别。UA字符串可以被伪造,而且新设备层出不穷,解析规则需要不断维护。更可靠的做法是让客户端主动上报关键能力,比如
X-Screen-Width、X-Supports-WebP。
3.2 上下文存储:ThreadLocal、RequestScope还是显式传参
采集到的上下文信息存在哪里,这是一个看似简单但很容易踩坑的问题。我见过三种做法,各有适用场景。
ThreadLocal方案:在Java生态里很常见,把上下文对象绑定到当前线程,业务代码随时随地可以取。优点是方便,不用改方法签名;缺点是容易在异步场景下丢失上下文,而且如果线程池复用线程,忘记清理会导致上下文污染。我一般只在纯同步的请求处理链路里用,而且一定会配合拦截器做afterCompletion清理。
RequestScope方案:在Spring等框架里,把上下文对象声明为请求作用域的Bean,通过依赖注入获取。优点是生命周期由框架管理,不容易泄漏;缺点是不是所有地方都能方便地注入,比如静态工具类里就拿不到。适合框架支持完善、代码结构比较规范的项目。
显式传参方案:把上下文对象作为方法的第一个参数,一路传递下去。优点是清晰、可控、没有隐式依赖;缺点是方法签名会变长,代码看起来有点啰嗦。我现在的项目里越来越倾向于这种方案,尤其是在核心业务逻辑里。因为显式传参让依赖关系一目了然,测试的时候也容易构造不同的上下文。
实际项目中,我经常混用:在入口层用ThreadLocal或RequestScope采集和暂存,到了核心业务层再显式地作为参数传递。这样既减少了重复代码,又保证了核心逻辑的可测试性。
3.3 模式决策:规则放在哪里,怎么保证可维护性
模式决策是context-mode的核心。决策逻辑放在哪里,直接决定了这套机制的可维护性。我的建议是分层决策:
- 第一层:硬编码的默认规则。比如“没有携带任何上下文信息时,走最保守的模式(最小数据集、最低限流阈值)”。这层规则写在代码里,不轻易改动,作为兜底。
- 第二层:配置文件里的业务规则。比如“移动端且VIP用户走精简模式”“大促期间所有非核心接口降级”。这层规则放在配置中心,可以动态调整,但需要经过审核流程。
- 第三层:运行时动态规则。比如“当前数据库连接池使用率超过80%时,所有查询走缓存模式”。这层规则由监控系统触发,自动生效,但要有熔断机制防止误判。
决策逻辑的实现上,我推荐用责任链模式。每个决策节点只关心自己负责的维度,返回“匹配/不匹配/继续”三种结果。这样新增一个决策维度只需要加一个节点,不会影响已有逻辑。而且责任链的每个节点都可以单独测试,排查问题也方便。
实操心得:决策规则一定要有日志。每次模式切换都记录“谁(哪个规则)在什么时间、基于什么上下文、把模式从A切到了B”。线上出问题时,这些日志能帮你快速定位是规则配置错了,还是上下文采集错了。
3.4 模式执行:如何让业务代码感知不到模式切换
模式决策完成后,接下来是执行。理想情况下,业务代码不应该关心当前是什么模式,它只负责处理数据,模式相关的差异由框架层处理掉。这需要用到一些设计技巧。
对于数据裁剪类的模式差异,可以用序列化层拦截。比如定义一个@ContextAware注解,标记在DTO的字段上,然后自定义序列化器根据当前模式决定是否输出该字段。这样业务代码只需要正常返回完整对象,序列化层自动做裁剪。
对于逻辑分支类的模式差异,可以用策略模式+工厂。业务代码注入一个策略接口,工厂根据当前模式返回对应的实现。业务代码调用接口方法,不关心具体实现。新增模式时只需要加一个实现类并注册到工厂。
对于资源分配类的模式差异,可以用装饰器模式。比如一个查询服务,基础实现走数据库,装饰器根据模式决定是否加缓存、是否加限流、是否降级。业务代码注入的是装饰后的服务,感知不到底层差异。
这些技巧的共同点是:把模式相关的复杂度从业务代码里移出去,放到框架层或基础设施层。业务代码越干净,后续维护和测试的成本就越低。
4. 实操过程:从零搭建一套context-mode机制
4.1 环境准备与技术选型
假设我们要在一个典型的Java后端项目里落地context-mode。技术栈是Spring Boot + MyBatis + Redis。这个组合在国内互联网公司里很常见,参考价值比较大。
需要引入的依赖不多,核心是Spring Web和AOP。如果要用配置中心,可以加上Nacos或Apollo的客户端。规则引擎方面,如果规则不复杂,自己写一个轻量的解析器就够了,没必要上Drools这种重型工具。我试过用Drools,学习曲线陡峭,而且性能开销不小,后来换成了自己写的YAML规则解析器,维护起来反而更顺手。
项目结构上,我建议单独建一个context包,里面放上下文对象、采集器、决策器和执行器。业务代码通过一个门面类(Facade)来获取当前模式或执行模式相关操作,不直接依赖内部实现。这样后续替换实现方案时,业务代码不用改。
4.2 定义上下文对象与采集器
先定义上下文对象。我一般用一个RequestContext类,包含设备信息、用户信息、业务信息和运行时信息四个部分。每个部分用独立的子对象表示,方便扩展。
public class RequestContext { private DeviceInfo device; private UserInfo user; private BizInfo biz; private RuntimeInfo runtime; // getters and setters } public class DeviceInfo { private String clientType; // web, ios, android, miniapp private int screenWidth; private boolean supportsWebP; // ... }采集器实现为一个Spring拦截器,在preHandle阶段执行。采集顺序是:先从请求头读取显式信息,再用User-Agent等做补充推断,最后填充默认值。
public class ContextCollector implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { RequestContext ctx = new RequestContext(); // 显式采集 ctx.getDevice().setClientType(request.getHeader("X-Client-Type")); // 隐式补充 if (ctx.getDevice().getClientType() == null) { ctx.getDevice().setClientType(parseFromUserAgent(request.getHeader("User-Agent"))); } // 默认值 if (ctx.getDevice().getClientType() == null) { ctx.getDevice().setClientType("web"); } ContextHolder.set(ctx); return true; } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { ContextHolder.clear(); } }这里用了一个ContextHolder,内部是ThreadLocal。注意afterCompletion里一定要清理,否则线程池复用时会出问题。这个坑我踩过,当时一个用户看到了另一个用户的数据,排查了半天才发现是上下文没清理。
4.3 实现模式决策器
决策器我推荐用责任链+配置的方式。先定义一个决策节点接口:
public interface DecisionNode { DecisionResult decide(RequestContext ctx); } public class DecisionResult { private boolean matched; private String mode; private String reason; // ... }然后每个节点负责一个维度的判断。比如设备维度节点:
public class DeviceDecisionNode implements DecisionNode { private Map<String, String> deviceModeMapping; // 从配置加载 @Override public DecisionResult decide(RequestContext ctx) { String clientType = ctx.getDevice().getClientType(); String mode = deviceModeMapping.get(clientType); if (mode != null) { return DecisionResult.matched(mode, "device:" + clientType); } return DecisionResult.notMatched(); } }配置可以放在YAML里:
context: rules: - name: mobile-lite condition: "device.clientType == 'ios' || device.clientType == 'android'" mode: "lite" - name: vip-full condition: "user.level >= 3" mode: "full"如果不想引入表达式引擎,可以用简单的条件匹配器,支持==、>=、in等基本操作。我试过用SpEL(Spring Expression Language),功能够用,但性能一般,而且有安全风险(表达式注入)。后来换成了自己写的解析器,只支持有限的语法,安全可控。
决策器的执行逻辑是:按顺序遍历所有节点,第一个匹配的节点决定模式。如果都不匹配,走默认模式。这里要注意节点的顺序,一般把更具体的规则放在前面,更通用的放在后面。
4.4 模式执行器的落地
模式执行器负责根据决策结果执行对应的逻辑。我一般用AOP+注解的方式,让业务代码无感知。
定义一个注解:
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface ContextMode { String value() default ""; // 指定模式,空表示由决策器决定 }然后写一个切面:
@Aspect @Component public class ContextModeAspect { @Around("@annotation(contextMode)") public Object around(ProceedingJoinPoint pjp, ContextMode contextMode) throws Throwable { RequestContext ctx = ContextHolder.get(); String mode = contextMode.value().isEmpty() ? decisionEngine.decide(ctx) : contextMode.value(); ModeExecutor executor = executorFactory.get(mode); return executor.execute(pjp, ctx); } }ModeExecutor接口定义执行逻辑,不同模式有不同的实现。比如LiteModeExecutor会裁剪返回数据,FullModeExecutor返回完整数据。业务代码只需要在方法上加@ContextMode注解,剩下的交给框架。
注意:AOP切面要注意执行顺序。如果和其他切面(比如事务切面、日志切面)一起用,要确保上下文采集切面在最外层执行,否则上下文可能还没准备好。
4.5 配置动态更新与灰度发布
规则配置放在配置中心后,需要支持动态更新。我的做法是监听配置变更事件,重新构建决策链。重建过程中用读写锁保护,避免决策时读到半成品。
灰度发布方面,可以给规则加一个enabled开关和percentage字段。比如新规则只对10%的用户生效,观察一段时间没问题再全量。百分比的计算可以用用户ID的哈希值取模,保证同一用户始终命中同一分组。
- name: new-recommend-mode condition: "user.level >= 2" mode: "recommend-v2" enabled: true percentage: 10这个机制在大促前特别有用。你可以提前把新模式的规则配好,但只对内部用户或小流量生效,等验证没问题再逐步放大。
5. 常见问题与排查技巧实录
5.1 上下文丢失:异步场景下的经典坑
问题现象:在同步接口里能正常获取上下文,但一旦用了@Async、CompletableFuture或线程池,上下文就变成null了。
原因:ThreadLocal是线程绑定的,异步任务在新线程里执行,自然拿不到原线程的ThreadLocal。
解决方案:用TransmittableThreadLocal(阿里开源的TTL)替代普通ThreadLocal,它支持线程池场景下的上下文传递。或者手动在提交异步任务前捕获上下文,在任务内部重新设置。
RequestContext ctx = ContextHolder.get(); CompletableFuture.runAsync(() -> { ContextHolder.set(ctx); try { // 业务逻辑 } finally { ContextHolder.clear(); } });我现在的做法是封装一个ContextAwareExecutor,提交任务时自动做上下文传递和清理,业务代码不用关心。
5.2 模式冲突:多个规则同时匹配怎么办
问题现象:配置了多条规则,某个请求同时满足多条规则的条件,系统不知道该走哪个模式。
原因:决策链没有定义优先级,或者优先级定义不清晰。
解决方案:给每条规则加一个priority字段,数字越小优先级越高。决策时按优先级排序,取第一个匹配的。同时,在决策日志里记录所有匹配的规则,方便排查为什么走了某个模式。
| 规则名 | 优先级 | 条件 | 模式 |
|---|---|---|---|
| vip-full | 10 | user.level >= 3 | full |
| mobile-lite | 20 | device.clientType in (ios, android) | lite |
| default | 999 | 无条件 | basic |
这样即使一个VIP用户从移动端访问,也会走full模式,因为vip-full的优先级更高。
5.3 性能问题:决策链太长导致响应变慢
问题现象:接入context-mode后,接口平均响应时间增加了20ms以上。
原因:决策链节点太多,每个节点都做复杂的条件判断;或者配置解析在每次请求时都执行。
解决方案:第一,把配置解析结果缓存起来,只在配置变更时重新解析。第二,对决策结果做缓存,相同的上下文组合直接返回缓存结果。第三,把不常变的决策节点(比如设备类型判断)的结果缓存在上下文对象里,避免重复计算。
我实测下来,优化后决策耗时可以控制在1ms以内。关键是要避免在决策链里做IO操作,所有需要的数据都应该在采集阶段准备好。
5.4 排查工具:如何快速定位模式切换问题
问题现象:用户反馈看到的数据不对,怀疑是模式切换错了。
排查思路:第一步,查决策日志,看这个请求走了哪个模式、匹配了哪条规则。第二步,查上下文采集日志,看采集到的上下文信息是否正确。第三步,如果上下文正确但模式不对,检查规则配置是否有误。第四步,如果都正确但数据还是不对,检查模式执行器是否有bug。
我一般会在响应头里加一个X-Context-Mode字段,标明本次请求走的模式。这样前端和测试人员不用查日志就能知道当前模式。线上环境可以只对内部用户开放这个字段,避免信息泄露。
实操心得:在开发环境里加一个调试接口,输入用户ID和请求头信息,直接返回决策结果和匹配的规则。这个工具在联调阶段能省很多沟通成本。
5.5 常见问题速查表
| 问题 | 可能原因 | 排查方法 | 解决方案 |
|---|---|---|---|
| 上下文为null | 异步场景ThreadLocal丢失 | 检查是否用了线程池 | 用TTL或手动传递 |
| 模式不符合预期 | 规则优先级配置错误 | 查决策日志 | 调整priority |
| 响应变慢 | 决策链有IO操作 | 看耗时分布 | 缓存配置和结果 |
| 数据裁剪错误 | 序列化器未生效 | 检查注解和切面顺序 | 调整切面order |
| 配置更新不生效 | 缓存未刷新 | 查配置监听日志 | 手动触发刷新 |
6. 进阶玩法:context-mode在AI应用里的新实践
6.1 对话上下文与模式切换的结合
在大模型应用里,context-mode有了新的用武之地。一个AI助手需要根据对话上下文决定回答策略:是直接回答、检索知识库、调用外部工具,还是转人工。这本质上就是模式切换。
我的做法是定义一个DialogContext,包含对话历史、用户画像、当前意图、情绪状态等信息。然后定义一组回答模式:direct-answer(直接回答)、rag-answer(检索增强)、tool-call(工具调用)、handoff(转人工)。决策器根据上下文选择模式,执行器调用对应的处理链路。
这里的关键是上下文窗口的管理。对话历史不能无限增长,需要做摘要和裁剪。我一般保留最近N轮完整对话,更早的对话做摘要后作为背景信息。摘要的触发时机和粒度也需要根据模式调整:direct-answer模式可以少带背景,rag-answer模式需要更多背景来构造检索query。
6.2 多模态场景下的上下文融合
当AI应用同时处理文本、图片、语音时,上下文变得更加复杂。不同模态的信息需要融合成一个统一的上下文对象,供决策器使用。
我的经验是分层融合:第一层做模态内的特征提取,比如文本提取意图和实体,图片提取物体和场景,语音提取文字和情绪。第二层做跨模态对齐,把不同模态的信息映射到同一个语义空间。第三层做上下文聚合,生成最终的决策依据。
这个过程中,context-mode的价值在于:不同模态组合可以走不同的处理模式。比如纯文本对话走轻量模式,图文混合走多模态模式,语音输入走实时转写模式。每种模式的资源消耗和处理延迟差异很大,通过模式切换可以做到成本和体验的平衡。
6.3 上下文缓存与成本优化
AI应用的推理成本很高,尤其是大模型调用。通过context-mode,可以对不同模式设置不同的缓存策略。比如direct-answer模式的结果可以缓存较长时间,因为常见问题答案相对固定;rag-answer模式的结果缓存时间短一些,因为知识库可能更新;tool-call模式一般不缓存,因为工具返回结果实时性要求高。
我实测过一个客服AI助手,引入模式化缓存后,大模型调用次数减少了40%,而用户满意度没有下降。关键是要做好缓存key的设计,把上下文的关键维度都纳入key的计算,避免不同上下文命中同一缓存导致答案错乱。
7. 我踩过的坑与最后分享的几个技巧
第一个坑是过度设计。刚开始做context-mode时,我试图把所有能想到的上下文维度都纳入决策,结果决策链有二十多个节点,配置规则上百条,维护起来极其痛苦。后来砍掉了大量低频维度,只保留真正影响决策的少数几个,系统反而更稳定。我的建议是:从最简单的场景开始,只解决当前最痛的问题,后续按需扩展。
第二个坑是忽视默认模式。有一次配置更新时漏掉了一个规则,导致部分请求没有匹配到任何模式,系统直接抛异常。后来我强制要求决策器必须有默认模式兜底,而且默认模式要足够保守,保证系统不崩。
第三个坑是上下文信息泄露。早期我把完整的上下文对象序列化后放到了响应头里,方便调试。结果上线后发现响应头里包含了用户ID和内部租户信息,有安全风险。后来改成只输出模式名称和规则ID,敏感信息一律不输出。
最后分享一个小技巧:给模式起个好记的名字。不要用mode-1、mode-2这种无意义的编号,而是用mobile-lite、vip-full、degraded-cache这种一看就懂的名字。这在排查问题和沟通时能省很多解释成本。而且名字本身就能传达模式的意图,新同事看代码时更容易理解。
这套context-mode机制我在三个项目里落地过,从最初的简单拦截器到后来的配置化决策链,迭代了两年多。最大的体会是:不要追求一步到位,而是让机制随着业务一起生长。先解决最痛的点,再逐步完善。等到业务复杂到一定程度时,你会发现这套机制已经成为系统不可或缺的基础设施了。