此设计模式系列,均为用通俗易懂的语言抛砖引玉,不作深究,最近在系统学习ASM字节码框架,里面用到了各种Visitor类,大量应用了访问者设计模式,特记录此篇文章。
1、基本介绍:
- 封装某些作用于某种数据结构中各元素的操作,它可以在不改变数据结构的前提下定义作用于这些数据元素的新的操作。
- 主要解决:稳定的数据结构和易变的操作的解耦。
- 假如一个对象中存在着一些与本对象不相干(或者关系较弱)的操作,可以使用访问者模式把这些操作封装到访问者中去,这样便避免了这些不相干的操作污染这个对象。
2、成员:
- 一个称为元素(Element),另一个称为访问者(Visitor)。
- 元素有一个accept()方法,访问者有一个visit( )方法。
- Element#accept(Visitor visitor) :元素的accept()会接收访问者作为参数,在这个方法中调用访问者的visit( )方法,在visit()中会将元素自身作为参数传递给访问者,由元素本身决定是否访问。
3、具体:
3.1、场景:
- 如果老师教学反馈得分大于等于85分、学生成绩大于等于90分,则可以入选成绩优秀奖;如果老师论文数目大于8、学生论文数目大于2,则可以入选科研优秀奖。
- 在这个例子中,老师和学生就是Element,他们的数据结构稳定不变。从上面的描述中,我们发现,对数据结构的操作是多变的,一会儿评选成绩,一会儿评选科研,这样就适合使用访问者模式来分离数据结构和操作。
3.2、实现:
3.2.1、创建抽象元素Element:
public interface Element {
void accept(Visitor visitor);
}
3.2.2、创建具体元素:创建两个具体元素 Student 和 Teacher,分别实现 Element 接口
public class Student implements Element {
private String name;
private int grade;
private int paperCount;
public Student(String name, int grade, int paperCount) {
this.name = name;
this.grade = grade;
this.paperCount = paperCount;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
......
}
public class Teacher implements Element {
private String name;
private int score;
private int paperCount;
public Teacher(String name, int score, int paperCount) {
this.name = name;
this.score = score;
this.paperCount = paperCount;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
......
}
3.2.3、创建抽象访问者Visitor:
public interface Visitor {
void visit(Student student);
void visit(Teacher teacher);
}
3.2.4、创建具体访问者:创建一个根据分数评比的具体访问者 GradeSelection,实现 Visitor 接口
public class GradeSelection implements Visitor {
@Override
public void visit(Student student) {
if (student != null && student.getGrade() >= 90) {
System.out.println(student.getName() + "的分数是" + student.getGrade() + ",荣获了成绩优秀奖。");
}
}
@Override
public void visit(Teacher teacher) {
if (teacher != null && teacher.getScore() >= 85) {
System.out.println(teacher.getName() + "的分数是" + teacher.getScore() + ",荣获了成绩优秀奖。");
}
}
}
3.2.5、访问者代码调用:
public class VisitorClient {
public static void main(String[] args) {
Element element = new Student("lunn", 98, 5);
Visitor visitor = new GradeSelection();
element.accept(visitor);
}
}