概要
访问者模式是一种将数据操作和数据结构分离的设计模式。
访问者模式的基本思想是 软件系统中有一个由许多对象构成的、比较稳定的对象结构,这些对象的类都拥有accept方法用来接受访问者对象的访问。访问者是一个接口或者抽象类,它拥有一个visit方法,这个方法访问到的对象结构中,不同的元素做出不同的处理。在对象结构的一次访问过程中,我们遍历整个对象结构,对每一个元素都实施accept方法,在每一个元素的accept方法中会调用访问者的visit方法,从而使访问者得以处理对象结构中的每一个元素,我们可以针对对象结构设计不同的访问者类来完成不同的操作,从而达到区别对待。
定义
封装一些作用于某种数据结构中各个元素的操作,它可以在不改变这个数据结构的前提下定义作用于这些元素的新的操作。
使用场景
- 对象结构比较稳定,但经常需要在此对象结构上定义新的操作。
- 需要对一个对象结构中的对象进行不同的并且不相关的操作,而需要避免这些操作交叉而影响数据,也不希望在增加新操作时修改这些类。
UML类图
角色介绍
Visitor:接口或者抽象类,它定义了对每一个元素(Element)访问的行为,它的参数就是可以访问的元素,它的方法个数理论上与元素的个数是一致的,因此,访问者模式要求元素的类族要稳定的,如果经常添加、移除元素类,必然会导致频繁修改Visitor接口, 如果出现这种情况,则说明 不适合使用访问者模式。
ConcreteVisitor:具体的访问者,它需要给出对每一个元素类访问时,所产生的具体行为。
Element:元素接口或者接口类,它定义了一个接受访问者(accept)方法,其意义是指每一个元素都要可以被访问者访问。
ElementA、ElementB:具体的元素类,它提供了接受访问方法的具体实现,而这个具体的实现,通常情况下是使用访问者提供的访问该元素类的方法。
ObjectStructure:定义当中所提到的对象结构,对象结构是一个抽象表述,它内部管理了元素结合,并且可以迭代这些元素供访问者访问。
示例代码
创建Visitor
Visitor包含两个抽象方法visit,参数分别是LiberalStu、ScienceStu,相当于子类重载了visit这个方法,意味着LiberalStu、ScienceStu的访问会调用不同的方法,以此来区别对待。
public abstract class Visitor {
abstract void visit(LiberalStu stu);
abstract void visit(ScienceStu stu);
}
创建具体Visitor: HeadTeacher和LiberalTeacher
HeadTeacher访问者关注所有学生的成绩,而LiberalTeacher只关注理科学生的成绩
public class HeadTeacher extends Visitor {
@Override
void visit(LiberalStu stu) {
System.out.println("HeadTeacher:"+ stu.toString());
}
@Override
void visit(ScienceStu stu) {
System.out.println("HeadTeacher:"+ stu.toString());
}
}
public class LiberalTeacher extends Visitor {
@Override
void visit(LiberalStu stu) {
System.out.println("LiberalTeacher:"+ stu.toString());
}
@Override
void visit(ScienceStu stu) {
}
}
创建元素抽象类Stu
抽象类Stu包含方法accept,表示接收访问者访问,由子类实现
public abstract class Stu {
private int id;
private String name;
private double chinese;
public Stu(int id, String name, double chinese) {
this.id = id;
this.name = name;
this.chinese = chinese;
}
abstract void accept(Visitor visitor);
}
创建具体元素类
// 理科学生
public class LiberalStu extends Stu {
// 理综
private double comprehensive;
public LiberalStu(int id, String name, double chinese, double comprehensive) {
super(id, name, chinese);
this.comprehensive = comprehensive;
}
public double getComprehensive() {
return comprehensive;
}
public void setComprehensive(double comprehensive) {
this.comprehensive = comprehensive;
}
@Override
void accept(Visitor visitor) {
visitor.visit(this);
}
@Override
public String toString() {
return "LiberalStu{" +
"comprehensive=" + comprehensive +
'}';
}
}
// 文科学生
public class ScienceStu extends Stu {
// 文综
private double science;
public ScienceStu(int id, String name, double chinese, double science) {
super(id, name, chinese);
this.science = science;
}
public double getScience() {
return science;
}
public void setScience(double science) {
this.science = science;
}
@Override
void accept(Visitor visitor) {
visitor.visit(this);
}
@Override
public String toString() {
return "ScienceStu{" +
"science=" + science +
'}';
}
}
测试类
public class Test {
public static void main(String[] args) {
StuStructor stuStructor = new StuStructor();
stuStructor.showSocre(new HeadTeacher());
stuStructor.showSocre(new LiberalTeacher());
}
}
测试Log
HeadTeacher:LiberalStu{comprehensive=89.4}
HeadTeacher:ScienceStu{science=78.0}
HeadTeacher:LiberalStu{comprehensive=98.0}
HeadTeacher:ScienceStu{science=77.0}
HeadTeacher:ScienceStu{science=89.0}
LiberalTeacher:LiberalStu{comprehensive=89.4}
LiberalTeacher:LiberalStu{comprehensive=98.0}