访问者模式(别名:虚拟构造)
表示一个作用于某对象结构中的各个元素的操作。它可以在不改变各个元素的类的前提下定义作用于这些元素的新操作。
Visitor Pattern
Represent an operation to be preformed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operator.
类图
模式的结构与使用
访问者模式的结构中包括五种角色。
+ 抽象元素(Element):一个抽象类,该类定义了接口访问者的accept操作。
+ 具体元素(Concrete Element):Element的子类。
+ 对象结构(Object Structure):一个集合,用于存放Element对象,提供遍历它自己的方法。
+ 抽象访问者(Visitor):一个接口,该接口定义操作对象(Concrete Element的实例)的方法。
简单的例子
Element的抽象类Student.java
package Visitor;
public abstract class Student {
public abstract void accept(Visitor v);
}
ConcreteElement的实现类GraduateStudent.java
package Visitor;
public class GraduateStudent extends Student {
private double math,english,physics;
private 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);
}
}
ConcreteElement的实现类Undergraduate.java
package Visitor;
public class Undergraduate extends Student {
private double math,english;
private 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);
}
}
Visitor的接口类Visitor.java
package Visitor;
public interface Visitor {
public void visit(Undergraduate stu);
public void visit(GraduateStudent stu);
}
ConcreteVisitor的实现类Company.java
package Visitor;
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() + "被录用");
}
}
}
测试类Application.java
package Visitor;
import java.util.ArrayList;
import java.util.Iterator;
public class Application {
public static void main(String[] args) {
Visitor visitor = new Company();
ArrayList<Student> studentList = new ArrayList<Student>();
studentList.add(new Undergraduate(88, 67, "张三"));
studentList.add(new Undergraduate(90, 98, "李四"));
studentList.add(new Undergraduate(85, 92, "王五"));
studentList.add(new GraduateStudent(88, 70, 87, "赵六"));
studentList.add(new GraduateStudent(90, 95, 82, "周吴"));
Iterator<Student> iter = studentList.iterator();
while (iter.hasNext()) {
Student stu = iter.next();
stu.accept(visitor);
}
}
}
执行效果图
双重分派
访问者模式在不改变类的情况下可有效地增加其上的操作,为了达到这样的效果,使用了一种称为“双重分派”的技术:在访问者模式中,被访问者,即Element角色element,首先调用accept(Visitor visitor)方法接受访问者,而被接受的访问者visitor再调用visit(Element element)方法访问当前对象。
访问者模式的优点
- 可以在不改变一个集合中元素的类的情况下,增加新的施加于该元素上的新操作。
- 可以将集合中各个元素的某些操作集中到访问者中,不仅便于集合的维护,也有利于集合中元素的复用。
注:在访问者模式中,每增加一个Element角色的子类,都意味着需要在Visitor角色中给出访问该子类的实例的visit()的方法。
适用访问者模式的情景
- 一个对象结构中,比如某个集合中,包含很多对象,想对集合中的对象增加一些新的操作。
- 需要对集合中的对象进行很多不同的并且不相关的操作,而又不想修改对象的类,就可以使用访问者模式。访问者模式可以在Visitor类中集中定义一些关于集合中对象的操作。