发布时间:2026/8/13 1:32:33
设计模式 22 · 三个冷门模式:中介者、访问者、解释器 行为型的最后三个模式——中介者(Mediator)、访问者(Visitor)、解释器(Interpreter)——我们放在一篇里集中讲。为什么合并?因为它们是二十三式里最冷门、适用面最窄的三个:中介者容易被滥用成上帝类,访问者结构复杂且限制苛刻,解释器则是公认几乎用不到的一个。把它们放一起,不是敷衍,而是要传递一个和全系列一脉相承的态度:这三个模式,你更需要知道的是它们解决什么问题、以及为什么大多数时候你不该用它们,而不是把它们的模板背下来到处套。所以这一篇的写法和前面不同:每个模式我只讲清三件事——它解决什么问题、核心怎么做、以及为什么适用面这么窄,点到为止,不铺长。读完你能认出它们、知道它们的定位,并在极少数真正需要的场景里想起它们,就够了。目录中介者:让一群对象别再两两纠缠访问者:数据结构稳定,操作却不断加解释器:为一种小语言定义文法三个模式的共同点:适用面都很窄一、中介者:让一群对象别再两两纠缠中介者模式解决什么问题?当一堆对象之间两两直接通信、相互引用时,它们会织成一张乱麻般的网——每个对象都要认识一大堆别的对象,任何一个改动都可能牵连一片。中介者的思路:引入一个中介者对象,让所有对象都只跟中介者通信,而不再彼此直接引用,把网状的多对多关系,变成星型的一对多。一个订单场景的例子:下单页的组件联动。下单页上有一堆相互关联的组件:选了优惠券,总金额要变;改了收货地址,运费要变,运费变了总金额又要变;改了商品数量,金额、运费、优惠资格全要重算……如果每个组件都直接持有并调用其他组件,就是一张可怕的网。用中介者,让每个组件的变化都通知下单页中介者,由中介者统一协调这个变了、该让哪些组件跟着更新:// 中介者:统一协调各组件的联动publicclassOrderPageMediator{privateCouponComponentcoupon;privateAddressComponentaddress;privateAmountComponentamount;// ... 持有各组件// 某个组件变了,通知中介者,由它决定联动谁publicvoidchanged(Componentsource){if(sourcecoupon){amount.recalculate();}if(sourceaddress){amount.recalculate();/* 还有运费等 */}// 协调逻辑集中在这里}}// 组件不再直接调别的组件,只通知中介者publicclassCouponComponent{privateOrderPageMediatormediator;publicvoidselect(){// ... 选优惠券mediator.changed(this);// 只告诉中介者我变了,不管谁联动}}好处很清楚:组件之间彻底解耦了,每个组件只认识中介者,不认识其他组件;所有的联动规则集中在中介者一处,清晰可查;加一个新组件,只需让它接入中介者。这和第 11 篇的外观模式有点像(都是加一个中间层),但意图不同:外观是单向的(简化外部对子系统的调用),中介者是双向的(协调内部一群对等对象的相互通信)。为什么它适用面窄、还容易被滥用?最大的风险是——中介者本身会膨胀成一个上帝类。因为所有协调逻辑都往中介者里塞,组件越多、联动越复杂,中介者就越臃肿,最后变成一个几百上千行、什么都管、谁都不敢碰的巨无霸。你只是把分散在各处的耦合,转移成了高度集中在一个类里的复杂度。所以中介者的适用场景很挑:只有当对象间确实是多对多的复杂交互、且交互逻辑适合集中管理时才用;如果对象关系本来就简单、或只是单向依赖,用它纯属自找麻烦。现实里 GUI 框架的表单联动、聊天室(用户通过服务器中转消息,而非两两直连)是它比较合适的场景。二、访问者:数据结构稳定,操作却不断加访问者模式解决什么问题?当你有一个稳定的数据结构(元素的种类基本固定),但需要不断给它增加新的操作时,访问者能让你在不修改元素类的前提下,新增操作。它的核心手法有点绕:把操作从元素类里抽出来,封装成一个个独立的访问者;元素只提供一个accept(visitor)方法,把自己交给访问者去处理。一个订单场景的例子:对订单集合做多种统计/导出操作。假设订单里有不同类型的元素(实物商品、虚拟商品、服务),你需要对它们做各种操作:算总价、导出 Excel、生成报表、统计重量……而且这些操作会不断新增。如果把每个操作都写进元素类,那每加一个操作,所有元素类都要改。访问者反过来:// 访问者接口:为每种元素类型定义一个 visit 方法publicinterfaceOrderVisitor{voidvisit(PhysicalItemitem);voidvisit(VirtualItemitem);}// 每个操作是一个访问者publicclassPriceVisitorimplementsOrderVisitor{voidvisit(PhysicalItemitem){/* 算实物价 */}voidvisit(VirtualItemitem){/* 算虚拟价 */}}publicclassExportVisitorimplementsOrderVisitor{/* 导出逻辑 */}// 元素只提供 accept,把自己交给访问者publicclassPhysicalItemimplementsItem{publicvoidaccept(OrderVisitorvisitor){visitor.visit(this);}}于是新增一个操作(比如统计重量),只需写一个新的WeightVisitor,所有元素类一个字都不用改。这就是访问者的价值——把操作这个变化维度,从元素类里彻底解放出来。为什么它适用面极窄?因为它有一个致命的倾斜性(和第 4 篇抽象工厂的倾斜性异曲同工):它对增加操作友好,但对增加元素类型极其敌视。新增一个操作 → 加一个访问者,爽;但新增一种元素类型(比如加个ServiceItem)→ 你得回去修改每一个访问者接口和所有实现,加上对新元素的visit方法——牵一发动全身,彻底违反开闭。所以访问者的适用前提非常苛刻:元素种类必须高度稳定(几乎不变),而操作会频繁增加。满足这个前提的场景本就不多(编译器的 AST 处理是经典例子:语法树节点类型固定,但要对它做类型检查、代码生成、优化等很多种操作)。加上它那套accept/visit的双分派结构本身就绕、可读性差,所以业务开发里极少用到。看到它能认出、知道它解决稳定结构 多变操作即可。三、解释器:为一种小语言定义文法解释器模式解决什么问题?当你需要处理一种简单的、自定义的小语言(比如一套规则表达式、一种查询语法)时,解释器提供一种方式:为这个语言定义一套文法,把每条文法规则表示成一个类,然后用这些类的对象组成一棵语法树,通过遍历这棵树来解释执行表达式。一个订单场景的例子:优惠规则表达式。假设运营想灵活配置优惠规则,比如金额100 AND 会员这样的表达式。解释器会把它拆成一棵树:AND是一个节点,左边是金额100(一个表达式),右边是会员(一个表达式),每种表达式是一个实现了interpret()的类,递归地解释求值:publicinterfaceExpression{booleaninterpret(Contextctx);// 解释:在给定上下文下求值}// 与 表达式publicclassAndExpressionimplementsExpression{privateExpressionleft,right;publicbooleaninterpret(Contextctx){returnleft.interpret(ctx)right.interpret(ctx);// 递归解释子表达式}}// 金额大于 表达式、是会员 表达式 ... 各是一个类你会发现,它的结构本质上就是第 10 篇组合模式(树形结构 递归)——解释器可以看作组合模式在’语言解释’这个特定场景的应用。为什么它几乎用不到?三个原因:其一,适用面极其狭窄——只有需要解释一种自定义小语言这一种场景才用得上,而这种需求本就罕见。其二,类爆炸——文法规则稍微一多,就要定义一大堆表达式类,复杂文法下根本维护不了。其三,有更好的替代——真要处理复杂表达式/语言,现实中都用成熟的工具:正则表达式、脚本引擎(如 Groovy、JS 引擎)、规则引擎(如 Drools)、或专门的解析器生成器(ANTLR),它们比手写解释器强大和健壮得多。所以解释器是二十三式里公认最少用的一个。它的价值更多是思想启发(理解语言是怎么被解析执行的),而非实战工具。了解它是什么、知道真要做这事有更好的轮子,就足够了。四、三个模式的共同点:适用面都很窄把这三个模式放一起收个尾,它们其实共享一个特征,也正是我们合并讲的原因:适用场景都非常窄,且都有明显的反噬风险。模式解决什么为什么少用中介者多对多交互 → 集中协调中介者易膨胀成上帝类访问者稳定结构 多变操作加元素类型就牵一发动全身;结构绕解释器解释自定义小语言场景罕见 类爆炸 有更好的轮子这三个模式,恰恰是全系列别过度设计这条主线最好的注脚。它们不是高级“厉害的模式,恰恰相反,它们是最需要克制的模式——因为它们结构复杂、限制苛刻,一旦用错场景,带来的复杂度远超收益。真正成熟的做法,不是我学会了访问者所以要找机会用”,而是我知道访问者的存在,但我清楚我这个场景的元素类型还会变,所以我不用它。知道一个模式什么时候不该用,和知道它怎么用,同等重要——甚至更重要。用一张图把这三个冷门模式的定位和别用它的信号钉在一起:小结。这一篇把行为型里最冷门的三个模式集中讲了:中介者用一个中介者集中协调一群对象的多对多交互,把网状耦合变星型,但要警惕它膨胀成上帝类;访问者把操作从稳定的数据结构里抽出来、以便不改元素就新增操作,但它对新增元素类型极度敌视、结构也绕,业务里极少用;解释器为一种自定义小语言建语法树来解释执行,但场景罕见、易类爆炸、且有正则/脚本引擎/规则引擎等更好的替代,是最少用的一个。它们共同的教训呼应全系列的主线——这些模式最需要的是克制,知道什么时候不该用它们,比会用更重要。下一篇是整个「设计模式拆解」系列的收尾总纲:我们会盘点 JDK/Spring/MyBatis 源码里的模式、集中辨析那些容易混淆的成对模式、再谈一次过度设计,把二十三个模式和七大原则串成一张完整的地图。

相关新闻

2026/8/13 1:32:33

先进过程控制(APC)在半导体良率提升中的核心作用与实践指南

1. 项目概述:当良率遇到瓶颈,我们该看向哪里?在晶圆制造的漫长链条里,良率(Yield)是最终决定一切商业成败的“圣杯”。产线上的工程师们每天都在和光刻对准、薄膜厚度、刻蚀均匀性这些具体的工艺参数搏斗&a…

2026/8/13 1:32:33

3分钟上手:B站视频下载神器BiliDownloader全面指南

3分钟上手:B站视频下载神器BiliDownloader全面指南 【免费下载链接】BiliDownloader BiliDownloader是一款界面精简,操作简单且高速下载的b站下载器 项目地址: https://gitcode.com/gh_mirrors/bi/BiliDownloader 还在为无法保存喜欢的B站视频而烦…

2026/8/13 1:32:33

基于SpringBoot的智能物业管理系统设计与实现

1. 项目概述小区物业管理系统是现代社区管理的重要工具,它通过信息化手段整合物业资源、提升服务效率。基于Java和SpringBoot的智能化物业管理系统,能够实现业主信息管理、物业费收缴、报修处理、设备维护等核心功能,同时支持移动端访问&…

2026/8/13 2:37:36

天同天梁双星组合在寅申宫的命理解析与人生启示

1. 从“荫星”到“福寿”:天同天梁双星组合的核心意象在紫微斗数的星曜体系中,双星同宫的组合往往能碰撞出比单星更为复杂、深刻的能量场。天同与天梁在寅、申二宫同度,便是这样一个极具代表性的组合。初次接触这个组合,很多人会简…

2026/8/13 2:37:36

JASP统计分析软件:让复杂统计变得像聊天一样简单

JASP统计分析软件:让复杂统计变得像聊天一样简单 【免费下载链接】jasp-desktop JASP aims to be a complete statistical package for both Bayesian and Frequentist statistical methods, that is easy to use and familiar to users of SPSS 项目地址: https:…

2026/8/13 2:37:36

猫抓插件:浏览器资源嗅探与智能下载的终极解决方案

猫抓插件:浏览器资源嗅探与智能下载的终极解决方案 【免费下载链接】cat-catch 猫抓 浏览器资源嗅探扩展 / cat-catch Browser Resource Sniffing Extension 项目地址: https://gitcode.com/GitHub_Trending/ca/cat-catch 还在为网页视频无法保存而烦恼吗&am…

2026/8/13 2:37:36

Loop Engineering 的艺术,详解智能体落地的四种循环

智能体之所以有用,是因为它们能在现实世界中采取行动,帮我们把工作自动化。但要让智能体可靠地执行真正有价值的任务,光有一个好模型还不够——它需要一套精心设计的 外部工作框架(Harness),并且这套框架必…

2026/8/13 2:37:36

GraphRAG 图记忆要取代向量检索?开发者选型三条路讲透

8 月 10 号,OpenAI 把 GPT-5.6 Luna 向免费用户开放了,默认模型换成 Luna,文本聊天无限量,朋友圈又是一轮刷屏。但让我想写点东西的,是同一周技术圈里另一条线,「图记忆取代向量检索」的讨论明显升温了。 …

2026/8/13 2:32:36

中层管理柔性制衡

中层管理柔性制衡,核心是“刚柔并济”:对事用制度刚性立底线,对人用柔性方式引导自律,避免硬管控引发抵触,也防无约束导致混乱,最终实现团队自驱与组织平衡。 1. 对事:有形制度立规矩&#xff0…

2026/8/12 10:37:12

如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南 【免费下载链接】chinese_license_plate_generator 中国车牌生成器 项目地址: https://gitcode.com/gh_mirrors/ch/chinese_license_plate_generator 中国车牌生成器是一个基于Python的开源项目&#xff0c…

2026/8/12 5:35:25

当 LLM 遇见大文档:主流开源项目如何处理上下文超限

从 Agentic Loop 到 Repo Map,七种策略与六类陷阱引言:128K vs 10MB 的硬冲突 2026 年的 LLM 上下文窗口已达到 128K ~ 1M token(≈ 0.5MB ~ 4MB 文本),但 LLM 想要处理的真实数据规模远远超过这个量级:真实…

2026/8/13 0:02:21

Prefix Cache

Prefix Cache(前缀缓存) 是大模型推理引擎(如 vLLM、SGLang、TensorRT-LLM)中用于跨请求复用已计算 KV Cache 的核心内存与计算优化技术。 它的核心目的在于:彻底消除重复 Prompt 的 Prefill 阶段计算,将首…

2026/8/13 0:02:21

VSCode插件精选:从AI补全到代码规范,打造高效开发环境

1. 项目概述:为什么说插件是VSCode的灵魂?如果你和我一样,每天有超过8小时的时间是在VSCode里度过的,那你肯定明白,一个顺手的开发环境有多重要。VSCode本身已经足够优秀了,但真正让它从“好用的编辑器”蜕…

2026/8/13 0:02:21

如何快速完成文件批量重命名:FreeReNamer终极指南

如何快速完成文件批量重命名:FreeReNamer终极指南 【免费下载链接】FreeReNamer 功能强大又易用的文件批量重命名软件 项目地址: https://gitcode.com/gh_mirrors/fr/FreeReNamer 你是否曾经面对成百上千个杂乱无章的文件感到头疼?传统的手动重命…

2026/8/10 11:20:30

实测才敢推 AI论文网站 2026最新测评与推荐

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。一、综…

2026/8/11 17:06:59

2026必备!AI论文网站测评:最新推荐与深度对比

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 一、…

2026/8/11 3:05:11

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

一天写完毕业论文在2026年已不再是天方夜谭。2026年最炸裂、实测能大幅提速的AI论文写作工具,覆盖选题构思、文献整理、内容生成、格式排版等核心场景,真正帮你高效搞定论文难题。 一、全流程王者:一站式搞定论文全链路(一天定稿首…