代码界的「海关检查」:访问者模式的签证艺术

代码界的「海关检查」:访问者模式的签证艺术


一、当对象开始「持证上岗」

想象这样的国际机场:

中国公民走自助通道,外国人走人工窗口;

行李要过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 城管巡逻:海关与片警的区别

维度 访问者模式 直接操作对象
操作权限 只读检查,不改动原结构 可能直接修改对象
扩展性 新增操作只需加访问者 需修改所有相关类
复杂度 双分派机制增加理解成本 简单直接
适用场景 对象结构稳定操作多变 操作与结构同步变化
现实类比 海关统一查验标准 片警各自为政

五、代码海关的真实战场

  1. 编译器设计

    • 语法树检查(类型检查、优化建议)
    • 不同后端生成(Java字节码、C代码)
  2. 文档处理

    • 格式转换(Word转PDF、Markdown转HTML)
    • 字数统计、敏感词扫描
  3. 游戏引擎

    • 场景对象渲染(不同画质方案)
    • 碰撞检测、物理模拟
  4. 金融系统

    • 风险审计(反洗钱、信用评估)
    • 报表生成(Excel、PDF、图表)
  5. GUI框架

    • UI组件导出为不同格式
    • 无障碍功能支持(屏幕阅读器适配)

六、防扣留指南(最佳实践)

  1. 保持元素稳定

    text 复制代码
    如果频繁新增ConcreteElement类型
    会导致所有Visitor需要修改 → 灾难!
  2. 避免操作耦合

    java 复制代码
    // 错误示范:在visit方法中修改元素状态
    void visit(TextElement text) {
        text.setContent(text.getContent().trim()); // 破坏元素结构
    }
  3. 使用组合访问者

    java 复制代码
    class 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方法类似...
    }
  4. 空对象访问者

    java 复制代码
    class NullVisitor implements DocVisitor {
        public void visit(TextElement text) {} // 静默处理
        public void visit(ImageElement image) {}
    }
  5. 与迭代器模式联用

    java 复制代码
    elements.forEach(element -> element.accept(visitor));

七、海关通关总结

访问者模式让代码成为优雅的边检官:

  • :用于对象结构稳定但操作多变的场景
  • :通过双分派实现动态绑定
  • 不要:在元素类频繁变动时使用
  • 不要:在访问者中修改元素状态

当你在IDE中看到"Code Analysis"时,请想起访问者模式------那个在后台默默扫描代码隐患的电子边检员!

相关推荐
float_六七1 小时前
IntelliJ IDEA双击Ctrl的妙用
java·ide·intellij-idea
能摆一天是一天3 小时前
JAVA stream().flatMap()
java·windows
颜如玉3 小时前
🤲🏻🤲🏻🤲🏻临时重定向一定要能重定向🤲🏻🤲🏻🤲🏻
java·http·源码
程序员爱钓鱼4 小时前
Go语言实战案例 — 工具开发篇:实现一个图片批量压缩工具
后端·google·go
程序员的世界你不懂5 小时前
【Flask】测试平台开发,新增说明书编写和展示功能 第二十三篇
java·前端·数据库
星空寻流年5 小时前
设计模式第一章(建造者模式)
java·设计模式·建造者模式
gb42152876 小时前
java中将租户ID包装为JSQLParser的StringValue表达式对象,JSQLParser指的是?
java·开发语言·python
曾经的三心草6 小时前
Python2-工具安装使用-anaconda-jupyter-PyCharm-Matplotlib
android·java·服务器
蒋星熠6 小时前
Flutter跨平台工程实践与原理透视:从渲染引擎到高质产物
开发语言·python·算法·flutter·设计模式·性能优化·硬件工程
Metaphor6926 小时前
Java 高效处理 Word 文档:查找并替换文本的全面指南
java·经验分享·word