在访问者模式(Visitor Pattern)中,我们使用了一个访问者类,它改变了元素类的执行算法。通过这种方式,元素的执行算法可以随着访问者改变而改变。这种类型的设计模式属于行为型模式。根据模式,元素对象已接受访问者对象,这样访问者对象就可以处理元素对象上的操作。
简单来说:访问者模式就是在不改变类的定义的前提上,来增加新的操作!
编写类的时候,可能在该类中编写了若干个实例方法,该类的对象通过调用这些实例方法操作其成员变量表明所产生的行为。在某些设计中,可能需要定义作用于类的成员变量的新操作,而且这个新操作不应当由该类中的某个实例方法来承担。比如,有一个Ammeter(电表)类,在Ammeter类中,electricAmount成员变量的值表示电量,showElectricAmount()方法返回electricAmount变量的值来收取电费。显然,不应该在Ammeter类中增加计算电费的方法(电表本身不能计算电费)。在实际生活中,应当由物业部门的“计表员”观察电表的用电量,然后按照收费标准计算出电费。而计表员就可以看做当前问题下访问者模式中的访问者。
1、对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作。
2、需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,也不希望在增加新操作时修改这些类。
访问者模式包括五种角色。
抽象元素(Element):一个抽象类,该类定义了接收访问者的accept操作;
具体元素(ConcreteElement):Element的子类;
对象结构(Object Structure):一个集合,用于存放Element对象,提供遍历它自己的方法;
抽象访问者(Visitor):一个接口,该接口定义操作对象(ConcreteElement的实例)的方法;
具体访问者(ConcreteVisitor):实现了Visitor接口的类。
以下通过一个简单的问题来描述怎样使用访问者模式,这个简单的问题是:公司考核若干个大学生和研究生,以决定是否录用。在这个问题中,大学生和研究生都有自己的成绩,但是他们不能依据自己的成绩制定标准,录用标准必须公司爱确定。
1.抽象元素
本问题中,抽象元素角色是Student类,代码如下所示:
public abstract class Student {
public abstract void accept(Visitor v);
}
2.具体元素
在本问题中,有两个具体元素,分别是Undergraduate和GraduateStudent类,这两个类分别表示大学生和研究生,二者的成就体系是不同的,代码如下所示:
Undergraduate.java
public class Undergraduate extends Student{
double math;
double english;
String name;
public Undergraduate(double math, double english, String name) {
this.math = math;
this.english = english;
this.name = name;
}
public double getMath() {
return math;
}
public double getEnglish() {
return english;
}
public String getName() {
return name;
}
@Override
public void accept(Visitor v) {
v.visit(this);
}
}
GraduateStudent.java
public class GraduateStudent extends Student{
double math;
double english;
double physics;
String name;
public GraduateStudent(double math, double english, double physics, String name) {
this.math = math;
this.english = english;
this.physics = physics;
this.name = name;
}
public double getMath() {
return math;
}
public double getEnglish() {
return english;
}
public double getPhysics() {
return physics;
}
public String getName() {
return name;
}
@Override
public void accept(Visitor v) {
v.visit(this);
}
}
3.对象结构(Object Structure)
本问题中,该角色是java.util包中的ArrayList集合。
4.抽象访问者(Visitor)
本问题中,抽象访问者接口是Visitor,代码如下所示:
public interface Visitor {
public void visit(Undergraduate stu);
public void visit(GraduateStudent stu);
}
5.具体访问者(ConcreteVisitor)
本问题中,具体访问者是公司Company,代码如下所示:
public class Company implements Visitor{
@Override
public void visit(Undergraduate stu) {
double math=stu.getMath();
double english = stu.getEnglish();
if(math>80 && english>90){
System.out.println(stu.getName()+"被录取");
}
}
@Override
public void visit(GraduateStudent stu) {
double math = stu.getMath();
double english = stu.getEnglish();
double physics = stu.getPhysics();
if(math>80 && english>90 && physics>70){
System.out.println(stu.getName()+"被录取");
}
}
}
6.测试程序
import java.util.ArrayList;
public class Application {
public static void main(String[] args) {
Visitor visitor=new Company();
ArrayList<Student> studentList=new ArrayList<>();
studentList.add(new Undergraduate("张三",67,88));
studentList.add(new Undergraduate("李四",90,99));
studentList.add(new GraduateStudent("王五",90,92,99));
studentList.add(new GraduateStudent("王麻子",80,90,92));
for (Student student : studentList) {
student.accept(visitor);
}
}
}
1.可以在不改变一个集合中元素的类的情况下,增加新的施加于该元素的新操作;
2.可以将集合中各个元素的某些操作集中到访问者中,不仅方便集合的维护,也有利于集合中元素的复用!