代码界的「海关检查」:访问者模式的签证艺术
一、当对象开始「持证上岗」
想象这样的国际机场:
中国公民走自助通道,外国人走人工窗口;
行李要过X光机,随身物品要单独安检;
防疫检查看健康码,边检查验护照...
访问者模式就像代码世界的海关系统------「你可以保持原样,但必须接受所有检查!」 让不同对象在不修改自身结构的情况下,接受各种外来操作的「签证审查」。
二、海关的检查流程(UML图)
java
┌─────────────┐ ┌─────────────┐
│ Element │ │ Visitor │
├─────────────┤ ├─────────────┤
│ +accept(v) │<───────┐ │ +visitA() │
└──────△──────┘ ├─┤ +visitB() │
│ │ └──────△──────┘
┌──────┴──────┐ │ ┌──────┴──────┐
│ Concrete │ │ │ Concrete │
│ ElementA │ │ │ Visitor1 │
└─────────────┘ │ └─────────────┘
└─────────────────┘
- 旅客(Element):被检查的对象(如代码中的数据结构)
- 海关(Visitor):定义检查操作的接口
- 中国公民(ConcreteElementA):具体被检查对象
- 安检仪(ConcreteVisitor1):具体检查逻辑实现
三、代码海关的验放大厅(场景实战)
1. 定义旅客协议(元素接口)
java
interface DocumentElement {
void accept(DocVisitor visitor); // 必须接受检查
}
// 具体旅客类型
class TextElement implements DocumentElement {
private String content;
public TextElement(String content) {
this.content = content;
}
public void accept(DocVisitor visitor) {
visitor.visit(this); // 走文本专用通道
}
public String getContent() { return content; }
}
class ImageElement implements DocumentElement {
private String url;
public ImageElement(String url) {
this.url = url;
}
public void accept(DocVisitor visitor) {
visitor.visit(this); // 走图片专用通道
}
public String getUrl() { return url; }
}
2. 制定检查标准(访问者接口)
java
interface DocVisitor {
void visit(TextElement text); // 文本检查规则
void visit(ImageElement image); // 图片检查规则
}
3. 部署检查设备(具体访问者)
java
// HTML导出检查员
class HtmlExportVisitor implements DocVisitor {
private StringBuilder html = new StringBuilder();
public void visit(TextElement text) {
html.append("<p>").append(text.getContent()).append("</p>\n");
}
public void visit(ImageElement image) {
html.append("<img src=\"").append(image.getUrl()).append("\">\n");
}
public String getHtml() {
return "<html>\n<body>\n" + html + "</body>\n</html>";
}
}
// 敏感词扫描仪
class SensitiveWordVisitor implements DocVisitor {
private int sensitiveCount;
public void visit(TextElement text) {
if(text.getContent().contains("vpn")) {
sensitiveCount++;
System.out.println("⚠️ 发现敏感词:" + text.getContent());
}
}
public void visit(ImageElement image) {
if(image.getUrl().contains("暴恐")) {
sensitiveCount++;
System.out.println("⚠️ 发现违规图片:" + image.getUrl());
}
}
public int getSensitiveCount() { return sensitiveCount; }
}
4. 通关验放演示
java
public class CustomHouse {
public static void main(String[] args) {
List<DocumentElement> doc = Arrays.asList(
new TextElement("欢迎使用VPN翻墙"),
new ImageElement("暴恐图片.jpg"),
new TextElement("今日天气晴")
);
// HTML签证官上岗
HtmlExportVisitor htmlVisitor = new HtmlExportVisitor();
doc.forEach(e -> e.accept(htmlVisitor));
System.out.println(htmlVisitor.getHtml());
// 网警巡查员上岗
SensitiveWordVisitor police = new SensitiveWordVisitor();
doc.forEach(e -> e.accept(police));
System.out.println("发现违规内容:" + police.getSensitiveCount() + "处");
}
}
四、访问者 vs 城管巡逻:海关与片警的区别
维度 | 访问者模式 | 直接操作对象 |
---|---|---|
操作权限 | 只读检查,不改动原结构 | 可能直接修改对象 |
扩展性 | 新增操作只需加访问者 | 需修改所有相关类 |
复杂度 | 双分派机制增加理解成本 | 简单直接 |
适用场景 | 对象结构稳定操作多变 | 操作与结构同步变化 |
现实类比 | 海关统一查验标准 | 片警各自为政 |
五、代码海关的真实战场
-
编译器设计:
- 语法树检查(类型检查、优化建议)
- 不同后端生成(Java字节码、C代码)
-
文档处理:
- 格式转换(Word转PDF、Markdown转HTML)
- 字数统计、敏感词扫描
-
游戏引擎:
- 场景对象渲染(不同画质方案)
- 碰撞检测、物理模拟
-
金融系统:
- 风险审计(反洗钱、信用评估)
- 报表生成(Excel、PDF、图表)
-
GUI框架:
- UI组件导出为不同格式
- 无障碍功能支持(屏幕阅读器适配)
六、防扣留指南(最佳实践)
-
保持元素稳定:
text如果频繁新增ConcreteElement类型 会导致所有Visitor需要修改 → 灾难!
-
避免操作耦合:
java// 错误示范:在visit方法中修改元素状态 void visit(TextElement text) { text.setContent(text.getContent().trim()); // 破坏元素结构 }
-
使用组合访问者:
javaclass ComboVisitor implements DocVisitor { private List<DocVisitor> visitors = new ArrayList<>(); void addVisitor(DocVisitor v) { visitors.add(v); } public void visit(TextElement text) { visitors.forEach(v -> v.visit(text)); } // 其他visit方法类似... }
-
空对象访问者:
javaclass NullVisitor implements DocVisitor { public void visit(TextElement text) {} // 静默处理 public void visit(ImageElement image) {} }
-
与迭代器模式联用:
javaelements.forEach(element -> element.accept(visitor));
七、海关通关总结
访问者模式让代码成为优雅的边检官:
- ✅ 要:用于对象结构稳定但操作多变的场景
- ✅ 要:通过双分派实现动态绑定
- ❌ 不要:在元素类频繁变动时使用
- ❌ 不要:在访问者中修改元素状态
当你在IDE中看到"Code Analysis"时,请想起访问者模式------那个在后台默默扫描代码隐患的电子边检员!