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

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


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

想象这样的国际机场:

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

行李要过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"时,请想起访问者模式------那个在后台默默扫描代码隐患的电子边检员!

相关推荐
bobz9651 分钟前
AI-2-1
后端
zilong_zzz3 分钟前
系统编程3(共享内存/信号量)
java·开发语言
字节源流13 分钟前
【RabbitMQ】死信队列
java·rabbitmq·java-rabbitmq
五行星辰20 分钟前
SAX解析XML:Java程序员的“刑侦破案式“数据处理
xml·java·开发语言
向哆哆24 分钟前
Java 开发工具:从 Eclipse 到 IntelliJ IDEA 的进化之路
java·eclipse·intellij-idea
你是狒狒吗1 小时前
HttpServletRequest是什么
java
你们补药再卷啦1 小时前
springboot 项目 jmeter简单测试流程
java·spring boot·后端
网安密谈1 小时前
SM算法核心技术解析与工程实践指南
后端
菜鸡且互啄691 小时前
sql 向Java的映射
java·开发语言
bobz9651 小时前
Keepalived 检查和通知脚本
后端