- 访问者模式
访问者模式是对象的行为模式,访问者模式的目的是封装一些施加于某种数据结构元素之上的操作,一旦这些操作需要修改,接受这个操作的数据结构则保持不变。换句话说就是把数据结构和需要对该数据结构进行的操作分离处理,当需要对当前数据结构做新的操作时,只需要修改操作部分而不需要修改数据结构的代码。 - 访问者模式的示意图
- 访问者模式所包含的角色
抽象访问者角色: 一般是抽象类或者是接口,为系统中每个元素定义了访问行为,他的参数就是可以访问的元素,理论上来讲,这里面所包含的方法与元素个数是一样的。
具体访问者角色:继承或者实现抽象访问角色,给出对每一个元素访问时所产生的行为。
抽象元素角色:一般是抽象类或者接口,定义了一个接受访问这角色的方法,主要作用是做到每个元素都能被访问者访问。
具体元素角色:继承或者事项抽象元素角色,实现接受访问的具体方法,一般是使用访问者提供的访问该元素类的方法。
对象结构角色:一般用于管理元素集合,并且可以迭代这些元素工访问者访问 - 示例代码
某系统可以实现教师奖励和学生奖励的审批(Award Check),如果教师发表论文数超过10篇或者学生论文超过2篇可以评选科研奖,如果教师教学反馈分大于等于90分或者学生平均成绩大于等于90分可以评选成绩优秀奖。试使用访问者模式设计该系统,以判断候选人集合中的教师或学生是否符合某种获奖要求。
- 抽象访问者角色:
public interface Award {
void visitorStudent(Student student);
void vivitorTeacher(Teacher teacher);
}
- 抽象元素角色:
public interface Person {
void accept(Award award);
}
- 具体元素角色:
学生:
public class Student implements Person {
private String name;
private int numOfPaper;
private float score;
public Student(String name, int numOfPaper, float score) {
this.name = name;
this.numOfPaper = numOfPaper;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getNumOfPaper() {
return numOfPaper;
}
public void setNumOfPaper(int numOfPaper) {
this.numOfPaper = numOfPaper;
}
public float getScore() {
return score;
}
public void setScore(float score) {
this.score = score;
}
@Override
public void accept(Award award) {
award.visitorStudent(this);
}
}
老师:
public class Teacher implements Person {
private String name;
private int numOfPaper;
private float score;
public Teacher(String name, int numOfPaper, float score) {
this.name = name;
this.numOfPaper = numOfPaper;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getNumOfPaper() {
return numOfPaper;
}
public void setNumOfPaper(int numOfPaper) {
this.numOfPaper = numOfPaper;
}
public float getScore() {
return score;
}
public void setScore(float score) {
this.score = score;
}
@Override
public void accept(Award award) {
award.vivitorTeacher(this);
}
}
- 具体访问者角色:
科研奖:
public class AwardCheckOne implements Award {
@Override
public void visitorStudent(Student student) {
int numOfPaper = student.getNumOfPaper();
float score = student.getScore();
String name = student.getName();
if(numOfPaper>2){
System.out.println("学生"+name+"可以评选科研奖!");
}
}
@Override
public void vivitorTeacher(Teacher teacher) {
int numOfPaper = teacher.getNumOfPaper();
float score = teacher.getScore();
String name = teacher.getName();
if(numOfPaper>10){
System.out.println("老师"+name+"可以评选科研奖!");
}
}
}
成绩优秀奖:
public class AwardCheckTwo implements Award {
@Override
public void visitorStudent(Student student) {
int numOfPaper = student.getNumOfPaper();
float score = student.getScore();
String name = student.getName();
if(score>=90){
System.out.println("学生"+name+"可以评选成绩优秀奖!");
}
}
@Override
public void vivitorTeacher(Teacher teacher) {
int numOfPaper = teacher.getNumOfPaper();
float score = teacher.getScore();
String name = teacher.getName();
if(score>=90){
System.out.println("老师"+name+"可以评选成绩优秀奖!");
}
}
}
- 对象结构角色:
public class PersonList {
private ArrayList<Person> personArrayList = null;
public PersonList() {
personArrayList = new ArrayList<Person>();
}
public void addPerson(Person person){
personArrayList.add(person);
}
//遍历访问 集合中的每一个对象
public void accept(Award award) {
for(Object obj : personArrayList){
((Person)obj).accept(award);
}
}
}
- 测试方法:
public class Main {
public static void main(String[] args) {
PersonList personList = new PersonList();
Person p1,p2,p3,p4;
p1 = new Student("张三",1,80);
p2 = new Student("李四",3,100);
p3 = new Teacher("王五",9,100);
p4 = new Teacher("呜呜呜",11,100);
personList.addPerson(p1);
personList.addPerson(p2);
personList.addPerson(p3);
personList.addPerson(p4);
personList.accept(new AwardCheckOne());
System.out.println("---------------分界线--------------------");
personList.accept(new AwardCheckTwo());
}
}
- 运行截图:
- 访问者模式的优缺点:
优点:符合单一职责原则,使得数据对象和操作解耦;添加新的操作或者新的访问者变得很容易,具有良好的可扩展性;相对来说更加具有灵活性和复用性。
缺点:增加新的元素变得困难,在该模式中,每增加一个新的元素,都要修改抽象访问这角色,违背了开闭原则。破坏了封装性,访问者模式要求访问者对象访问并调用每一个元素对象的操作,这意味着元素对象有时候必须暴露一些自己的内部操作和内部状态,否则无法供访问者访问。