当前位置: 首页 > news >正文

0132_访问者模式(Visitor)

访问者模式(Visitor)

意图

表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。

UML 图

Visitor

优点

  1. 开闭原则:容易添加新的访问者操作,无需修改元素类
  2. 单一职责原则:将相关行为集中到一个访问者对象中
  3. 灵活性:可以在运行时选择不同的访问者执行不同的操作
  4. 数据分离:访问者可以收集复杂的对象结构信息
  5. 扩展性好:新增访问者不会影响现有系统结构

缺点

  1. 元素接口变更困难:每增加一个新的元素类,都要在访问者接口中添加一个新的visit操作
  2. 破坏封装性:访问者通常需要访问元素的内部状态,可能破坏封装性
  3. 依赖具体类:访问者依赖具体元素类,而不是抽象接口
  4. 对象结构变化困难:如果对象结构经常变化,会导致需要修改所有访问者

代码示例

以人类和机器人的诊断维护系统为例:

1. 访问者接口 (Visitor)

// 访问者接口
public interface Visitor {void visitHuman(Human human);void visitRobot(Robot robot);String getReport();
}

2. 具体访问者类 (Concrete Visitors)

// 健康检查访问者
public class HealthCheckVisitor implements Visitor {private StringBuilder report = new StringBuilder();@Overridepublic void visitHuman(Human human) {report.append("=== 人类健康检查报告 ===\n");report.append("姓名: ").append(human.getName()).append("\n");report.append("年龄: ").append(human.getAge()).append("岁\n");report.append("心率: ").append(human.getHeartRate()).append("bpm\n");report.append("体温: ").append(human.getBodyTemperature()).append("°C\n");String status = human.getHeartRate() > 100 ? "⚠️ 心率过高" : human.getBodyTemperature() > 37.5 ? "⚠️ 发烧" : "✅ 健康";report.append("状态: ").append(status).append("\n\n");}@Overridepublic void visitRobot(Robot robot) {report.append("=== 机器人诊断报告 ===\n");report.append("型号: ").append(robot.getModel()).append("\n");report.append("序列号: ").append(robot.getSerialNumber()).append("\n");report.append("电池电量: ").append(robot.getBatteryLevel()).append("%\n");report.append("运行时间: ").append(robot.getOperatingHours()).append("小时\n");String status = robot.getBatteryLevel() < 20 ? "⚠️ 电量不足" : robot.getOperatingHours() > 10000 ? "⚠️ 需要维护" : "✅ 正常";report.append("状态: ").append(status).append("\n\n");}@Overridepublic String getReport() {return report.toString();}
}// 维护访问者
public class MaintenanceVisitor implements Visitor {private StringBuilder report = new StringBuilder();private double totalCost = 0;@Overridepublic void visitHuman(Human human) {report.append("=== 人类保养建议 ===\n");report.append("姓名: ").append(human.getName()).append("\n");if (human.getAge() > 40) {report.append("建议: 年度体检\n");totalCost += 500;}if (human.getHeartRate() > 90) {report.append("建议: 心血管检查\n");totalCost += 300;}report.append("预估费用: ¥").append(totalCost).append("\n\n");}@Overridepublic void visitRobot(Robot robot) {report.append("=== 机器人维护方案 ===\n");report.append("型号: ").append(robot.getModel()).append("\n");if (robot.getBatteryLevel() < 30) {report.append("建议: 更换电池\n");totalCost += 800;}if (robot.getOperatingHours() > 8000) {report.append("建议: 全面检修\n");totalCost += 2000;}if (robot.getOperatingHours() > 10000) {report.append("建议: 关键部件更换\n");totalCost += 5000;}report.append("预估费用: ¥").append(totalCost).append("\n\n");}@Overridepublic String getReport() {return "总维护费用: ¥" + totalCost + "\n" + report.toString();}
}// 升级访问者
public class UpgradeVisitor implements Visitor {private StringBuilder report = new StringBuilder();@Overridepublic void visitHuman(Human human) {report.append("=== 人类能力提升建议 ===\n");report.append("姓名: ").append(human.getName()).append("\n");if (human.getAge() < 30) {report.append("建议: 专业技能培训\n");report.append("预期效果: 职业技能提升20%\n");} else {report.append("建议: 健康管理课程\n");report.append("预期效果: 寿命延长5年\n");}report.append("\n");}@Overridepublic void visitRobot(Robot robot) {report.append("=== 机器人升级方案 ===\n");report.append("型号: ").append(robot.getModel()).append("\n");if (robot.getOperatingHours() < 5000) {report.append("建议: 软件系统升级\n");report.append("预期效果: 性能提升15%\n");} else {report.append("建议: 硬件模块升级\n");report.append("预期效果: 使用寿命延长3年\n");}report.append("\n");}@Overridepublic String getReport() {return report.toString();}
}

3. 元素接口和具体元素类

// 元素接口
public interface Element {void accept(Visitor visitor);String getName();
}// 人类
public class Human implements Element {private String name;private int age;private double heartRate;private double bodyTemperature;public Human(String name, int age, double heartRate, double bodyTemperature) {this.name = name;this.age = age;this.heartRate = heartRate;this.bodyTemperature = bodyTemperature;}@Overridepublic void accept(Visitor visitor) {visitor.visitHuman(this);}@Overridepublic String getName() {return name;}// Getter方法public int getAge() { return age; }public double getHeartRate() { return heartRate; }public double getBodyTemperature() { return bodyTemperature; }
}// 机器人
public class Robot implements Element {private String model;private String serialNumber;private int batteryLevel;private int operatingHours;public Robot(String model, String serialNumber, int batteryLevel, int operatingHours) {this.model = model;this.serialNumber = serialNumber;this.batteryLevel = batteryLevel;this.operatingHours = operatingHours;}@Overridepublic void accept(Visitor visitor) {visitor.visitRobot(this);}@Overridepublic String getName() {return model + "-" + serialNumber;}// Getter方法public String getModel() { return model; }public String getSerialNumber() { return serialNumber; }public int getBatteryLevel() { return batteryLevel; }public int getOperatingHours() { return operatingHours; }
}

4. 对象结构类

// 对象结构
public class DiagnosticCenter {private List<Element> elements = new ArrayList<>();public void addElement(Element element) {elements.add(element);}public void performDiagnosis(Visitor visitor) {System.out.println("开始诊断检查...\n");for (Element element : elements) {element.accept(visitor);}System.out.println(visitor.getReport());System.out.println("诊断完成\n");}public void showAllElements() {System.out.println("=== 诊断中心成员 ===");for (Element element : elements) {System.out.println("- " + element.getName());}System.out.println();}
}

5. 客户端代码

public class VisitorPatternDemo {public static void main(String[] args) {System.out.println("=== 访问者模式演示 - 人类和机器人诊断系统 ===\n");// 创建诊断中心DiagnosticCenter center = new DiagnosticCenter();// 添加人类和机器人center.addElement(new Human("张三", 35, 85, 36.8));center.addElement(new Human("李四", 45, 95, 37.2));center.addElement(new Robot("T-800", "001", 65, 12000));center.addElement(new Robot("R2-D2", "002", 15, 3000));// 显示所有成员center.showAllElements();// 执行健康检查System.out.println("执行健康检查:");center.performDiagnosis(new HealthCheckVisitor());// 执行维护检查System.out.println("执行维护检查:");center.performDiagnosis(new MaintenanceVisitor());// 执行升级建议System.out.println("执行升级建议:");center.performDiagnosis(new UpgradeVisitor());System.out.println("=== 演示完成 ===");}
}

在Spring的应用

在Spring框架中,访问者模式的应用体现在:

  1. Bean定义访问BeanDefinitionVisitor用于访问和修改bean定义
  2. 注解处理AnnotationMetadataVisitor用于访问类的注解信息
  3. 资源访问ResourceVisitor用于处理资源文件访问逻辑
  4. 数据访问:JPA和Hibernate中的访问者模式用于实体检查和验证
  5. 表达式解析:Spring Expression Language (SpEL) 使用访问者模式解析表达式
  6. AOP处理:切面编程中的访问者模式用于方法拦截和处理

总结

访问者模式通过将操作与对象结构分离,使得可以在不修改现有类的情况下添加新的操作。它特别适用于需要对一个复杂对象结构中的多个元素执行不同操作的场景,如诊断系统、编译器设计、文档处理等。虽然会增加系统复杂性,但提供了很好的扩展性和灵活性。

http://www.hskmm.com/?act=detail&tid=9209

相关文章:

  • 国内AI云市场:挤不进前三,生存将成问题!
  • P14053 [SDCPC 2019] Median 题解
  • lQueryDef查询Evaluate报该几何不包含M值问题。
  • 我的首个RCE漏洞发现之旅:Apache ActiveMQ远程代码执行实战
  • 北京市社保费用差额补缴计算工具
  • 使用自签名SSL证书有什么风险?
  • CDN可以使用iTrustSSL通配符证书吗?
  • OpenCvSharp基于颜色反差规避FBA面单贴标
  • AI CodeReview + Devops协同
  • 【API接口】最新可用手机号归属地查询接口
  • 【API接口】最新可用IP地址查询接口
  • UE5创建的对象无法用ai操控
  • 【API接口】最新可用喜马拉雅接口
  • 25/09/18 小结
  • 【API接口】最新可用番茄畅听接口
  • 【API接口】最新可用七猫短剧接口
  • 磁盘分析工具推荐(Wiztree)
  • 用FastAPI和Streamlit实现一个ChatBot
  • 搜索百科(2):Apache Solr — 企业级搜索的开源先锋
  • Markbook Day03
  • re分区为y盘,efi分区为z盘
  • 数组,java学习第五天
  • 文件结构与数据分析专项-解析
  • 销售能力——Steam平台我们应该做什么游戏?
  • 平静
  • 2025.9.18总结
  • Codeforces 2144F Bracket Groups 题解 [ 紫 ] [ AC 自动机 ] [ DP ] [ 构造 ]
  • Java进制,数据类型拓展Unicode编码学习
  • 9月18日总结
  • 【转】[IDEA] 调试时怎么判断使用哪个配置文件