访问者模式
简介
表示一个作用于某对象结构中的各元素的操作,可以在不改变各元素类的前提下定义新操作。
使用场景:
编译器的AST遍历
XML/DOM树操作
报表生成
文件系统遍历
实现要点:
双分派机制
访问者为每种元素定义visit()方法
元素实现accept()方法
UML
代码示例
访问者接口
public interface Visitor {
/**
* 访问工程师
*/
void visit(Engineer engineer);
/**
* 访问经理
*/
void visit(Manager manager);
/**
* 访问CEO
*/
void visit(CEO ceo);
}访问者实现
/**
* @author dcx
* @description 年度报告生成器访问者 - 具体访问者
* @create 2025-01-27
*/
public class AnnualReportGenerator implements Visitor {
private StringBuilder report;
public AnnualReportGenerator() {
report = new StringBuilder();
report.append("📊 ========== 年度报告 ==========\n");
}
@Override
public void visit(Engineer engineer) {
report.append("\n👨💻 工程师: ").append(engineer.getName()).append("\n");
report.append(" 职位: ").append(engineer.getPosition()).append("\n");
report.append(" 工作年限: ").append(engineer.getWorkingYears()).append("年\n");
report.append(" 年度代码量: ").append(engineer.getCodeLines()).append("行\n");
report.append(" 工作评价: 代码质量优秀,技术能力强\n");
System.out.println("✅ 已为 " + engineer.getName() + " 生成年度报告");
}
@Override
public void visit(Manager manager) {
report.append("\n👔 经理: ").append(manager.getName()).append("\n");
report.append(" 职位: ").append(manager.getPosition()).append("\n");
report.append(" 工作年限: ").append(manager.getWorkingYears()).append("年\n");
report.append(" 团队规模: ").append(manager.getTeamSize()).append("人\n");
report.append(" 完成项目: ").append(manager.getProjectCount()).append("个\n");
report.append(" 工作评价: 管理能力出色,团队协作良好\n");
System.out.println("✅ 已为 " + manager.getName() + " 生成年度报告");
}
@Override
public void visit(CEO ceo) {
report.append("\n👨💼 CEO: ").append(ceo.getName()).append("\n");
report.append(" 职位: ").append(ceo.getPosition()).append("\n");
report.append(" 工作年限: ").append(ceo.getWorkingYears()).append("年\n");
report.append(" 管理部门: ").append(ceo.getDepartmentCount()).append("个\n");
report.append(" 公司营收: ¥").append(String.format("%.2f", ceo.getCompanyRevenue())).append("万\n");
report.append(" 工作评价: 战略眼光卓越,领导力强\n");
System.out.println("✅ 已为 " + ceo.getName() + " 生成年度报告");
}
/**
* 获取报告内容
*/
public String getReport() {
report.append("\n========== 报告结束 ==========\n");
return report.toString();
}
}
/**
* @author dcx
* @description 绩效评估访问者 - 具体访问者
* @create 2025-01-27
*/
public class PerformanceEvaluator implements Visitor {
private int totalScore = 0;
private int count = 0;
@Override
public void visit(Engineer engineer) {
// 工程师绩效评分 = 工作年限分 + 代码质量分
int score = engineer.getWorkingYears() * 10 + (engineer.getCodeLines() / 10000) * 20;
if (score > 100) score = 100;
totalScore += score;
count++;
System.out.println("👨💻 工程师 " + engineer.getName() + " 的绩效评分: " + score + "分");
System.out.println(" 评级: " + getGrade(score));
}
@Override
public void visit(Manager manager) {
// 经理绩效评分 = 工作年限分 + 团队规模分 + 项目完成分
int score = manager.getWorkingYears() * 8 +
manager.getTeamSize() * 5 +
manager.getProjectCount() * 10;
if (score > 100) score = 100;
totalScore += score;
count++;
System.out.println("👔 经理 " + manager.getName() + " 的绩效评分: " + score + "分");
System.out.println(" 评级: " + getGrade(score));
}
@Override
public void visit(CEO ceo) {
// CEO绩效评分 = 工作年限分 + 部门管理分 + 公司营收分
int score = ceo.getWorkingYears() * 5 +
ceo.getDepartmentCount() * 8 +
(int)(ceo.getCompanyRevenue() / 10000) * 30;
if (score > 100) score = 100;
totalScore += score;
count++;
System.out.println("👨💼 CEO " + ceo.getName() + " 的绩效评分: " + score + "分");
System.out.println(" 评级: " + getGrade(score));
}
/**
* 根据分数获取评级
*/
private String getGrade(int score) {
if (score >= 90) return "S (优秀)";
if (score >= 80) return "A (良好)";
if (score >= 70) return "B (中等)";
if (score >= 60) return "C (及格)";
return "D (不及格)";
}
/**
* 获取平均绩效
*/
public double getAverageScore() {
return count == 0 ? 0 : (double) totalScore / count;
}
/**
* 重置统计
*/
public void reset() {
totalScore = 0;
count = 0;
}
}
/**
* @author dcx
* @description 薪资计算访问者 - 具体访问者
* @create 2025-01-27
*/
public class SalaryCalculator implements Visitor {
private double totalSalary = 0;
@Override
public void visit(Engineer engineer) {
// 工程师薪资 = 基本工资 + 工作年限奖金 + 代码行数奖金
double salary = 10000 + engineer.getWorkingYears() * 1000 + engineer.getCodeLines() / 1000.0 * 500;
totalSalary += salary;
System.out.println("👨💻 工程师 " + engineer.getName() + " 的薪资: ¥" + String.format("%.2f", salary));
System.out.println(" 工作年限: " + engineer.getWorkingYears() + "年");
System.out.println(" 代码行数: " + engineer.getCodeLines() + "行");
}
@Override
public void visit(Manager manager) {
// 经理薪资 = 基本工资 + 工作年限奖金 + 团队规模奖金 + 项目数量奖金
double salary = 20000 + manager.getWorkingYears() * 2000 +
manager.getTeamSize() * 500 + manager.getProjectCount() * 1000;
totalSalary += salary;
System.out.println("👔 经理 " + manager.getName() + " 的薪资: ¥" + String.format("%.2f", salary));
System.out.println(" 工作年限: " + manager.getWorkingYears() + "年");
System.out.println(" 团队规模: " + manager.getTeamSize() + "人");
System.out.println(" 项目数量: " + manager.getProjectCount() + "个");
}
@Override
public void visit(CEO ceo) {
// CEO薪资 = 基本工资 + 工作年限奖金 + 部门数量奖金 + 公司营收提成
double salary = 50000 + ceo.getWorkingYears() * 5000 +
ceo.getDepartmentCount() * 2000 + ceo.getCompanyRevenue() * 0.01;
totalSalary += salary;
System.out.println("👨💼 CEO " + ceo.getName() + " 的薪资: ¥" + String.format("%.2f", salary));
System.out.println(" 工作年限: " + ceo.getWorkingYears() + "年");
System.out.println(" 部门数量: " + ceo.getDepartmentCount() + "个");
System.out.println(" 公司营收: ¥" + String.format("%.2f", ceo.getCompanyRevenue()) + "万");
}
/**
* 获取总薪资
*/
public double getTotalSalary() {
return totalSalary;
}
/**
* 重置总薪资
*/
public void reset() {
totalSalary = 0;
}
}
员工接口
public interface Employee {
/**
* 接受访问者
*/
void accept(Visitor visitor);
/**
* 获取员工姓名
*/
String getName();
/**
* 获取员工职位
*/
String getPosition();
}
具体员工
/**
* @author dcx
* @description CEO类 - 具体元素
* @create 2025-01-27
*/
public class CEO implements Employee {
private String name;
private int workingYears;
private int departmentCount;
private double companyRevenue;
public CEO(String name, int workingYears, int departmentCount, double companyRevenue) {
this.name = name;
this.workingYears = workingYears;
this.departmentCount = departmentCount;
this.companyRevenue = companyRevenue;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override
public String getName() {
return name;
}
@Override
public String getPosition() {
return "CEO";
}
public int getWorkingYears() {
return workingYears;
}
public int getDepartmentCount() {
return departmentCount;
}
public double getCompanyRevenue() {
return companyRevenue;
}
}
/**
* @author dcx
* @description 工程师类 - 具体元素
* @create 2025-01-27
*/
public class Engineer implements Employee {
private String name;
private int workingYears;
private int codeLines;
public Engineer(String name, int workingYears, int codeLines) {
this.name = name;
this.workingYears = workingYears;
this.codeLines = codeLines;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override
public String getName() {
return name;
}
@Override
public String getPosition() {
return "工程师";
}
public int getWorkingYears() {
return workingYears;
}
public int getCodeLines() {
return codeLines;
}
}
/**
* @author dcx
* @description 经理类 - 具体元素
* @create 2025-01-27
*/
public class Manager implements Employee {
private String name;
private int workingYears;
private int teamSize;
private int projectCount;
public Manager(String name, int workingYears, int teamSize, int projectCount) {
this.name = name;
this.workingYears = workingYears;
this.teamSize = teamSize;
this.projectCount = projectCount;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override
public String getName() {
return name;
}
@Override
public String getPosition() {
return "经理";
}
public int getWorkingYears() {
return workingYears;
}
public int getTeamSize() {
return teamSize;
}
public int getProjectCount() {
return projectCount;
}
}
公司类
public class Company {
private String name;
private List<Employee> employees;
public Company(String name) {
this.name = name;
this.employees = new ArrayList<>();
}
/**
* 添加员工
*/
public void addEmployee(Employee employee) {
employees.add(employee);
System.out.println("➕ 添加员工: " + employee.getName() + " (" + employee.getPosition() + ")");
}
/**
* 移除员工
*/
public void removeEmployee(Employee employee) {
employees.remove(employee);
System.out.println("➖ 移除员工: " + employee.getName());
}
/**
* 接受访问者访问所有员工
*/
public void accept(Visitor visitor) {
System.out.println("\n🔍 访问者 [" + visitor.getClass().getSimpleName() + "] 正在访问公司员工...\n");
for (Employee employee : employees) {
employee.accept(visitor);
}
}
/**
* 获取员工数量
*/
public int getEmployeeCount() {
return employees.size();
}
/**
* 获取公司名称
*/
public String getName() {
return name;
}
/**
* 显示公司信息
*/
public void showCompanyInfo() {
System.out.println("\n🏢 公司: " + name);
System.out.println("👥 员工数量: " + employees.size());
System.out.println("员工列表:");
for (Employee employee : employees) {
System.out.println(" - " + employee.getName() + " (" + employee.getPosition() + ")");
}
}
}
使用方式
public class Test {
public static void main(String[] args) {
System.out.println("=== 访问者模式 - 公司员工管理示例 ===\n");
// 创建公司(对象结构)
Company company = new Company("科技创新公司");
System.out.println("【初始化公司员工】\n");
// 创建员工(元素)
Employee engineer1 = new Engineer("张三", 3, 50000);
Employee engineer2 = new Engineer("李四", 5, 80000);
Employee manager1 = new Manager("王五", 8, 10, 15);
Employee manager2 = new Manager("赵六", 6, 8, 12);
Employee ceo = new CEO("刘总", 15, 5, 50000);
// 添加员工到公司
company.addEmployee(engineer1);
company.addEmployee(engineer2);
company.addEmployee(manager1);
company.addEmployee(manager2);
company.addEmployee(ceo);
// 显示公司信息
company.showCompanyInfo();
// ========== 场景1:薪资计算 ==========
System.out.println("\n\n【场景1:薪资计算访问者】");
SalaryCalculator salaryCalculator = new SalaryCalculator();
company.accept(salaryCalculator);
System.out.println("\n💰 公司总薪资: ¥" + String.format("%.2f", salaryCalculator.getTotalSalary()));
System.out.println("💰 平均薪资: ¥" + String.format("%.2f", salaryCalculator.getTotalSalary() / company.getEmployeeCount()));
// ========== 场景2:绩效评估 ==========
System.out.println("\n\n【场景2:绩效评估访问者】");
PerformanceEvaluator performanceEvaluator = new PerformanceEvaluator();
company.accept(performanceEvaluator);
System.out.println("\n📈 平均绩效: " + String.format("%.1f", performanceEvaluator.getAverageScore()) + "分");
// ========== 场景3:年度报告生成 ==========
System.out.println("\n\n【场景3:年度报告生成访问者】");
AnnualReportGenerator reportGenerator = new AnnualReportGenerator();
company.accept(reportGenerator);
System.out.println("\n📄 年度报告内容:");
System.out.println(reportGenerator.getReport());
// ========== 场景4:添加新的访问者 ==========
System.out.println("\n【场景4:演示添加新访问者的便利性】");
System.out.println("假设现在需要添加新功能:统计员工信息");
System.out.println("✅ 只需要创建一个新的Visitor实现类");
System.out.println("❌ 不需要修改任何Employee类");
System.out.println("这就是访问者模式的优势!");
// ========== 对比不使用访问者模式 ==========
System.out.println("\n\n【对比:不使用访问者模式】\n");
System.out.println("❌ 不使用访问者模式:");
System.out.println(" - 需要在每个员工类中添加计算薪资、评估绩效等方法");
System.out.println(" - 添加新操作时,需要修改所有员工类");
System.out.println(" - 违反开闭原则,维护成本高");
System.out.println(" - 代码分散,难以统一管理");
System.out.println("\n 示例代码:");
System.out.println(" class Engineer {");
System.out.println(" double calculateSalary() { ... }");
System.out.println(" int evaluatePerformance() { ... }");
System.out.println(" String generateReport() { ... }");
System.out.println(" // 每次新增功能都要修改这里");
System.out.println(" }");
System.out.println("\n✅ 使用访问者模式:");
System.out.println(" - 员工类保持稳定,只需实现accept()方法");
System.out.println(" - 添加新操作只需创建新的Visitor");
System.out.println(" - 符合开闭原则,易于扩展");
System.out.println(" - 相关操作集中在访问者中");
System.out.println("\n 示例代码:");
System.out.println(" class Engineer {");
System.out.println(" void accept(Visitor visitor) {");
System.out.println(" visitor.visit(this);");
System.out.println(" }");
System.out.println(" // 添加新功能不需要修改这里");
System.out.println(" }");
// ========== 总结 ==========
System.out.println("\n\n=== 访问者模式说明 ===");
System.out.println("1. 访问者接口: Visitor - 为每种元素定义访问方法");
System.out.println("2. 具体访问者: SalaryCalculator等 - 实现具体的访问操作");
System.out.println("3. 元素接口: Employee - 定义accept()方法");
System.out.println("4. 具体元素: Engineer、Manager、CEO - 实现accept()");
System.out.println("5. 对象结构: Company - 存储元素集合");
System.out.println("\n=== 访问者模式优势 ===");
System.out.println("✅ 符合开闭原则: 添加新操作无需修改元素类");
System.out.println("✅ 相关操作集中: 同一操作的代码集中在一起");
System.out.println("✅ 易于添加新操作: 只需创建新的访问者");
System.out.println("✅ 数据结构稳定: 元素类结构保持稳定");
System.out.println("✅ 灵活性强: 可以为不同元素定义不同操作");
System.out.println("\n=== 访问者模式缺点 ===");
System.out.println("⚠️ 难以添加新元素: 需要修改所有访问者");
System.out.println("⚠️ 破坏封装: 访问者需要访问元素的内部数据");
System.out.println("⚠️ 依赖具体类: 访问者依赖具体的元素类");
System.out.println("\n=== 访问者模式应用场景 ===");
System.out.println("📌 编译器: AST遍历、代码生成、语义检查");
System.out.println("📌 文档处理: XML/DOM树的遍历和操作");
System.out.println("📌 报表生成: 不同格式的报表生成");
System.out.println("📌 对象持久化: 将对象保存为不同格式");
System.out.println("📌 数据统计: 对集合进行各种统计操作");
System.out.println("📌 权限检查: 对不同类型对象进行权限验证");
System.out.println("\n=== 访问者模式关键点 ===");
System.out.println("🔑 双分派: 运行时根据两个对象类型确定方法");
System.out.println("🔑 元素稳定: 元素类结构不经常变化");
System.out.println("🔑 操作多变: 经常需要添加新的操作");
System.out.println("🔑 accept()方法: 每个元素都要实现");
System.out.println("\n=== 双分派机制 ===");
System.out.println("第一次分派: employee.accept(visitor)");
System.out.println("第二次分派: visitor.visit(this)");
System.out.println("结果: 运行时确定具体的visit(Engineer)方法");
System.out.println("\n=== 何时使用访问者模式 ===");
System.out.println("✅ 对象结构稳定,不经常添加新元素");
System.out.println("✅ 经常需要对对象结构中的元素进行新操作");
System.out.println("✅ 需要对不同类型的元素执行不同操作");
System.out.println("✅ 对象结构包含多种类型的对象");
System.out.println("\n=== 何时不使用访问者模式 ===");
System.out.println("❌ 对象结构经常变化(添加新元素)");
System.out.println("❌ 元素类需要保持高度封装");
System.out.println("❌ 操作类型固定,不需要经常添加");
System.out.println("\n=== Java中的访问者模式应用 ===");
System.out.println("🔸 javax.lang.model.element.Element: Java编译器API");
System.out.println("🔸 org.w3c.dom.Node: DOM树遍历");
System.out.println("🔸 ASM/ByteBuddy: 字节码操作");
System.out.println("🔸 文件系统: java.nio.file.FileVisitor");
}
}Last updated
Was this helpful?