🚩什么是访问者设计模式?
访问者设计模式(Visitor Pattern) 是一种 行为型设计模式,它允许你将算法与对象结构分离,使得可以在不修改现有对象结构的情况下定义新的操作。访问者模式将相关操作集中到一个访问者对象中,而不是分散在各个元素类中。
使用场景
当需要对一个复杂对象结构(如组合结构)中的元素执行多种不同操作时
当对象结构中的元素类很少变化,但需要经常定义新操作时
当需要避免"污染"元素类,将相关操作集中管理时
适用于 编译器语法树分析、文档处理、报表生成 等场景
🚩访问者设计模式的特点
双重分派:通过两次方法调用实现动态绑定
操作集中化:将相关操作集中到访问者对象中
数据结构稳定:对象结构中的元素类很少变化
扩展性好:新增操作只需添加新的访问者类
访问权限高:访问者可以访问元素类的内部状态
🚩访问者设计模式的结构
访问者模式主要包含以下部分:
Visitor(抽象访问者)
:声明访问各种具体元素的接口ConcreteVisitor(具体访问者)
:实现抽象访问者声明的操作Element(抽象元素)
:定义accept方法接受访问者ConcreteElement(具体元素)
:实现accept方法ObjectStructure(对象结构)
:维护元素集合,提供访问入口
图例:
🚩访问者设计模式的优缺点
✅ 优点
增加新操作容易:只需增加新的访问者类
操作集中管理:相关行为集中在一个访问者中
访问者可以累积状态:在遍历过程中收集信息
符合单一职责原则:将相关操作分离到不同访问者
数据结构和操作解耦:数据结构可以独立演化
❌ 缺点
增加新元素类困难:每增加一个元素类都要修改访问者接口
破坏封装性:访问者需要访问元素的内部状态
违反依赖倒置原则:具体元素依赖具体访问者
复杂度高:对简单结构使用访问者模式可能过度设计
🚩访问者设计模式的Java实现
代码地址:GitHub
- 定义一个访问者接口
Visitor
/**
* @author hanson.huang
* @version V1.0
* @ClassName Visitor
* @Description 访问者接口
* @date 2025/3/26 14:02
**/
public interface Visitor {
public void visitStudent(Student student); // 访问学生
public void visitTeacher(Teacher teacher); // 访问老师
}
创建具体的访问者
Visitor1
和Visitor2
,用于实现不同的统计逻辑Visitor1
/** * @author hanson.huang * @version V1.0 * @ClassName Visitor1 * @Description 访问者1 * @date 2025/3/26 14:09 **/ public class Visitor1 implements Visitor { // 访问者1:统计年龄总和 private int studentAgeSum = 0; private int teacherAgeSum = 0; public int getStudentAgeSum() { return studentAgeSum; } public int getTeacherAgeSum() { return teacherAgeSum; } @Override public void visitStudent(Student student) { System.out.println("访问者1访问学生:" + student.getName() + " 年龄:" + student.getAge()); studentAgeSum += student.getAge(); } @Override public void visitTeacher(Teacher teacher) { System.out.println("访问者1访问老师:" + teacher.getName() + " 年龄:" + teacher.getAge()); teacherAgeSum += teacher.getAge(); } }
Visitor2
/** * @author hanson.huang * @version V1.0 * @ClassName Visitor2 * @Description 访问者2 * @date 2025/3/26 14:11 **/ public class Visitor2 implements Visitor {// 访问者2:求最高成绩和工龄 private int maxScore = -1; private int maxWorkYear = -1; public int getMaxScore() { return maxScore; } public int getMaxWorkYear() { return maxWorkYear; } @Override public void visitStudent(Student student) { System.out.println("访问者2访问学生:" + student.getName() + " 成绩:" + student.getScore()); maxScore = Math.max(maxScore, student.getScore()); } @Override public void visitTeacher(Teacher teacher) { System.out.println("访问者2访问老师:" + teacher.getName() + " 工龄:" + teacher.getWorkYear()); maxWorkYear = Math.max(maxWorkYear, teacher.getWorkYear()); } }
创建抽象类
Person
,定义Accept
方法接受访问者
/**
* @author hanson.huang
* @version V1.0
* @ClassName Person
* @Description 抽象类, 定义accept方法接受访问者
* @date 2025/3/26 14:04
**/
public abstract class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public abstract void Accept(Visitor visitor);
}
创建两个具体的元素
Student
和Teacher
,实现Accept
方法Student
/** * @author hanson.huang * @version V1.0 * @ClassName Student * @Description 具体元素 学生 * @date 2025/3/26 14:07 **/ public class Student extends Person { private int score; public Student(String name, int age, int score) { super(name, age); this.score = score; } public int getScore() { return score; } @Override public void Accept(Visitor visitor) { visitor.visitStudent(this); } }
Teacher
/** * @author hanson.huang * @version V1.0 * @ClassName Teacher * @Description 具体元素 老师 * @date 2025/3/26 14:08 **/ public class Teacher extends Person { private int workYear; public Teacher(String name, int age, int workYear) { super(name, age); this.workYear = workYear; } public int getWorkYear() { return workYear; } @Override public void Accept(Visitor visitor) { visitor.visitTeacher(this); } }
创建对象结构
PersonStructure
,维护元素集合并提供访问入口
/**
* @author hanson.huang
* @version V1.0
* @ClassName PersonStructure
* @Description 构造对象
* @date 2025/3/26 14:13
**/
public class PersonStructure {
private List<Person> personList = new ArrayList<>();
public PersonStructure() {
personList.add(new Student("张三", 20, 70));
personList.add(new Student("李四", 21, 80));
personList.add(new Student("王五", 22, 90));
personList.add(new Teacher("李老师", 26, 3));
personList.add(new Teacher("陈老师", 27, 4));
personList.add(new Teacher("刘老师", 28, 5));
}
public void Accept(Visitor visitor) {
for (Person person : personList) {
person.Accept(visitor);
}
}
}
- 测试访问者模式
/**
* @author hanson.huang
* @version V1.0
* @ClassName VisitorPattern
* @Description 测试访问者设计模式
* @date 2025/3/26 14:16
**/
public class VisitorPattern {
public static void main(String[] args) {
PersonStructure structure = new PersonStructure();
Visitor1 visitor1 = new Visitor1();
System.out.println("访问者1的访问记录:");
structure.Accept(visitor1);
System.out.println("学生年龄的总和:" + visitor1.getStudentAgeSum() + " 老师年龄的总和:" + visitor1.getTeacherAgeSum());
System.out.println("=========================================");
Visitor2 visitor2 = new Visitor2();
System.out.println("访问者2的访问记录:");
structure.Accept(visitor2);
System.out.println("学生的最高成绩:" + visitor2.getMaxScore() + " 老师的最高工龄:" + visitor2.getMaxWorkYear());
}
}
📌 运行结果
🚩代码总结
Visitor
接口定义了对不同元素的访问操作Visitor1
和Visitor2
是具体访问者,实现不同的统计逻辑Person
是抽象元素,定义accept
方法接受访问者Student
和Teacher
是具体元素,实现accept方法PersonStructure
是对象结构,维护元素集合并提供访问入口客户端可以轻松添加新的访问者而不修改现有类结构
🚩总结
访问者设计模式 将算法与对象结构分离,便于新增操作
核心是 双重分派机制,通过两次方法调用实现动态绑定
适用于 数据结构稳定但操作频繁变化 的场景
✅ Java源码中的应用场景:
Java注解处理器(APT):
- 处理注解时使用访问者模式遍历语法树
遍历文件系统时使用访问者模式
创作不易,不妨点赞、收藏、关注支持一下,各位的支持就是我创作的最大动力❤️