Java访问者模式实现优雅的对象结构处理
什么是访问者模式
访问者模式(Visitor Pattern)是一种行为型设计模式,它可以用于在不改变对象结构的前提下,对对象的元素进行新的操作。它将算法与对象结构分离开来,能够在不修改已有的类结构的情况下,向现有对象结构添加新的操作。
访问者模式的角色
访问者模式中包含如下角色:
-
抽象访问者(Visitor):为对象结构中每一个具体元素类ConcreteElement声明一个访问操作,从这个操作的名称或参数类型可以清楚知道它属于哪个具体的元素类。抽象访问者为对象结构中的每一个具体元素类ConcreteElement都定义了一个访问操作Visit()。
-
具体访问者(ConcreteVisitor):实现不同的访问操作,即对应不同的具体元素类ConcreteElement的访问操作。
-
抽象元素(Element):定义一个接受访问的方法accept(),它的参数是一个访问者Visitor对象。
-
具体元素(ConcreteElement):实现抽象元素提供的.accept()方法,其方法参数是具体的访问者对象。
-
对象结构(ObjectStructure):具体元素的集合,提供一个高层接口允许访问者对象访问它的元素。
访问者模式的优点
- 省去了修改现有代码,如若没有访问者模式,新增一个新功能,我们要在每个类里面加一个新的方法,所以代码变得不可控。
- 将有关行为集中到访问者中,再通过多态等技术操作具体元素。使得增加新的访问操作比较容易。
访问者模式的缺点
- 具体元素对访问者公布细节,违反了迪米特原则。
- 具体元素变更比较困难。如果需要增加一个ConcreteElement的子类,那么就需要更改所有的Visitor的子类。
访问者模式的应用场景
- 对象结构相对稳定,但其操作算法经常改变的场合。
Java实现访问者模式的示例
下面我们来看一个实现Java访问者模式的示例,假设我们有一个对象结构:一个学校,包括了不同的部门、学院、教师、学生等元素。现在我们需要对每个元素进行不同的操作,如打印信息、计算工资等。为了避免每个元素拥有不同的接口,我们可以使用访问者模式。
1. 创建元素类
我们先来定义学校中的各种元素。这里我们定义了School、Department、Teacher和Student四个类。
// School.java
public class School implements Element {
private List<Element> elements = new ArrayList<>();
public void add(Element element) {
elements.add(element);
}
public void remove(Element element) {
elements.remove(element);
}
public List<Element> getElements() {
return elements;
}
@Override
public void accept(Visitor visitor) {
for (Element e : elements) {
e.accept(visitor);
}
}
}
// Department.java
public class Department implements Element {
private String name;
private List<Element> elements = new ArrayList<>();
public Department(String name) {
this.name = name;
}
public void add(Element element) {
elements.add(element);
}
public void remove(Element element) {
elements.remove(element);
}
public List<Element> getElements() {
return elements;
}
public String getName() {
return name;
}
@Override
public void accept(Visitor visitor) {
visitor.visitDepartment(this);
for (Element e : elements) {
e.accept(visitor);
}
}
}
// Teacher.java
public class Teacher implements Element {
private String name;
private double salary;
public Teacher(String name, double salary) {
this.name = name;
this.salary = salary;
}
public String getName() {
return name;
}
public double getSalary() {
return salary;
}
@Override
public void accept(Visitor visitor) {
visitor.visitTeacher(this);
}
}
// Student.java
public class Student implements Element {
private String name;
private String id;
public Student(String name, String id) {
this.name = name;
this.id = id;
}
public String getName() {
return name;
}
public String getId() {
return id;
}
@Override
public void accept(Visitor visitor) {
visitor.visitStudent(this);
}
}
2. 创建访问者接口和具体访问者
我们定义一个Visitor接口,并为每个元素实现一个visit方法,用于具体的操作。这里我们定义了PrintVisitor和SalaryVisitor两个具体访问者:
public interface Visitor {
void visitDepartment(Department department);
void visitTeacher(Teacher teacher);
void visitStudent(Student student);
}
public class PrintVisitor implements Visitor {
private String content = "";
@Override
public void visitDepartment(Department department) {
content += "Department: " + department.getName() + "\n";
}
@Override
public void visitTeacher(Teacher teacher) {
content += "Teacher: " + teacher.getName() + "\n";
}
@Override
public void visitStudent(Student student) {
content += "Student: " + student.getName() + "\n";
}
public String getContent() {
return content;
}
}
public class SalaryVisitor implements Visitor {
private double salarySum = 0;
@Override
public void visitDepartment(Department department) {
}
@Override
public void visitTeacher(Teacher teacher) {
salarySum += teacher.getSalary();
}
@Override
public void visitStudent(Student student) {
}
public double getSalarySum() {
return salarySum;
}
}
3. 创建对象结构
我们定义一个School类作为对象结构容器,用于添加各种元素。
public class School implements Element {
private List<Element> elements = new ArrayList<>();
public void add(Element element) {
elements.add(element);
}
public void remove(Element element) {
elements.remove(element);
}
public List<Element> getElements() {
return elements;
}
@Override
public void accept(Visitor visitor) {
for (Element e : elements) {
e.accept(visitor);
}
}
}
4. 使用访问者模式进行访问
我们在调用访问对象时,只需要传入具体的访问者,对于不同的访问者,使用对应的visit函数即可完成对应操作。
public static void main(String[] args) {
School school = new School();
Department computerScience = new Department("Computer Science");
Department informationManagement = new Department("Information Management");
Teacher teacher1 = new Teacher("Jack", 8000);
Teacher teacher2 = new Teacher("Lucy", 9000);
Teacher teacher3 = new Teacher("Mike", 10000);
Student student1 = new Student("Tom", "20210001");
Student student2 = new Student("Jerry", "20210002");
Student student3 = new Student("Alex", "20210003");
computerScience.add(teacher1);
computerScience.add(student1);
computerScience.add(student2);
informationManagement.add(teacher2);
informationManagement.add(teacher3);
informationManagement.add(student3);
school.add(computerScience);
school.add(informationManagement);
PrintVisitor printVisitor = new PrintVisitor();
school.accept(printVisitor);
System.out.println(printVisitor.getContent());
SalaryVisitor salaryVisitor = new SalaryVisitor();
school.accept(salaryVisitor);
System.out.println("Total salary: " + salaryVisitor.getSalarySum());
}
输出结果为:
Department: Computer Science
Teacher: Jack
Student: Tom
Student: Jerry
Department: Information Management
Teacher: Lucy
Teacher: Mike
Student: Alex
Total salary: 27000.0
本文总结
本文介绍了访问者模式的定义和角色,以及它的优缺点和使用场景。在实现方面,我们通过一个简单的学校对象结构,介绍了Java访问者模式的使用方式。访问者模式将封装变得更加灵活,能够轻松扩展对象元素的操作。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java访问者模式实现优雅的对象结构处理 - Python技术站