对于系统中的某些对象,它们存储在同一个集合中,且具有不同的类型,而且对于该集合中的对象,可以接受一类称为访问者的对象来访问,而且不同的访问者其访问方式有所不同,访问者模式为解决这类问题而诞生。
访问者模式(Visitor Pattern):表示一个作用于某对象结构中的各元素的操作,它使我们可以在不改变各元素的类的前提下定义作用于这些元素的新操作。访问者模式是一种对象行为型模式。
访问者模式中对象结构存储了不同类型的元素对象,以供不同访问者访问。
访问者模式包括两个层次结构,一个是访问者层次结构,提供了抽象访问者和具体访问者,一个是元素层次结构,提供了抽象元素和具体元素。
相同的访问者可以以不同的方式访问不同的元素,相同的元素可以接受不同访问者以不同访问方式访问。在访问者模式中,增加新的访问者无须修改原有系统,系统具有较好的可扩展性。
package 访问者模式;
//抽象访问者类
public abstract class Visitor {
protected String name;
public void setName(String name){
this.name = name;
}
public abstract void visit(Apple apple);
public abstract void visit(Book book);
}
package 访问者模式;
//具体访问者类
public class Customer extends Visitor{
@Override
public void visit(Apple apple) {
System.out.println("顾客"+ name + "选苹果");
}
@Override
public void visit(Book book) {
System.out.println("顾客"+ name + "买书");
}
}
package 访问者模式;
//具体访问者类
public class Saler extends Visitor {
@Override
public void visit(Apple apple) {
System.out.println("收银员"+ name + "给苹果过秤,然后计算价格。");
}
@Override
public void visit(Book book) {
System.out.println("收银员"+ name + "计算书本的价格。");
}
}
package 访问者模式;
//抽象元素类
public interface Product {
public void accept(Visitor visitor);
}
package 访问者模式;
//具体元素类
public class Book implements Product {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
package 访问者模式;
//具体元素类
public class Apple implements Product {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
package 访问者模式;
import java.util.ArrayList;
import java.util.Iterator;
//对象结构类
public class BuyBasket {
private ArrayList list = new ArrayList();
public void accept(Visitor visitor){
Iterator i = list.iterator();
while (i.hasNext()){
((Product)i.next()).accept(visitor);
}
}
public void addProduct(Product product){
list.add(product);
}
public void removeProduct(Product product){
list.remove(product);
}
}
package 访问者模式;
import 工厂方法模式2.XMLUtil;
public class client {
public static void main(String[] args) {
Product b1 = new Book();
Product b2 = new Book();
Product b3 = new Apple();
Visitor visitor;
BuyBasket basket = new BuyBasket();
basket.addProduct(b1);
basket.addProduct(b2);
basket.addProduct(b3);
visitor = (Visitor) XMLUtil.getBean();
visitor.setName("Danny");
basket.accept(visitor);
}
}
实例二:奖励审批系统
某高校奖励审批系统可以实现教师奖励和学生奖励的审批(AwardCheck),如果教师发表论文数超过10篇或者学生论文超过2篇可以评选科研奖,如果教师教学反馈分大于等于90分或者学生平均成绩大于等于90分可以评选成绩优秀奖,使用访问者模式设计该系统,以判断候选人集合中的教师或学生是否符合某种获奖要求。
package 访问者模式2;
//抽象访问者类
public abstract class AwardCheck {
public abstract void visit(Teacher teacher);
public abstract void visit(Student student);
}
package 访问者模式2;
//具体访问者类
public class ExcellenceAwardCheck extends AwardCheck{
@Override
public void visit(Teacher teacher) {
if(teacher.getFeedbackScore()>=90){
System.out.println(teacher.getName() + "可评选为教师成绩优异奖。");
}
}
@Override
public void visit(Student student) {
if(student.getScore()>=90){
System.out.println(student.getName() + "可评选为学生成绩优异奖。");
}
}
}
package 访问者模式2;
//具体访问者类
public class ScientificAwardCheck extends AwardCheck {
@Override
public void visit(Teacher teacher) {
if(teacher.getFeedbackScore()>=10){
System.out.println(teacher.getName() + "可评选为教师科研奖。");
}
}
@Override
public void visit(Student student) {
if(student.getPaperAmount()>=2){
System.out.println(student.getName()+"可评选为学生科研奖。");
}
}
}
package 访问者模式2;
//抽象元素类
public interface Person {
public void accept(AwardCheck check);
}
package 访问者模式2;
//具体元素类
public class Student implements Person {
private String name;
private int paperAmount;
private double score;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPaperAmount() {
return paperAmount;
}
public void setPaperAmount(int paperAmount) {
this.paperAmount = paperAmount;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
public void accept(AwardCheck check){
check.visit(this);
}
}
package 访问者模式2;
//具体元素类
public class Teacher implements Person {
private String name;
private int paperAmount;
private double feedbackScore;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPaperAmount() {
return paperAmount;
}
public void setPaperAmount(int paperAmount) {
this.paperAmount = paperAmount;
}
public double getFeedbackScore() {
return feedbackScore;
}
public void setFeedbackScore(double feedbackScore) {
this.feedbackScore = feedbackScore;
}
public void accept(AwardCheck check){
check.visit(this);
}
}
package 访问者模式2;
import java.util.ArrayList;
import java.util.Iterator;
//对象结构
public class CandidateList {
private ArrayList<Person> list = new ArrayList<>();
public void addPerson(Person person){
list.add(person);
}
public void removePerson(Person person){
list.remove(person);
}
public void accept(AwardCheck check){
Iterator i = list.iterator();
while (i.hasNext()){
((Person)i.next()).accept(check);
}
}
}
package 访问者模式2;
public class client {
public static void main(String[] args) {
CandidateList list = new CandidateList();
AwardCheck sac,eac;
Teacher teacher = new Teacher();
Student student = new Student();
teacher.setName("大冰");
teacher.setFeedbackScore(92);
teacher.setPaperAmount(15);
student.setName("大童");
student.setPaperAmount(2);
student.setScore(85);
list.addPerson(teacher);
list.addPerson(student);
sac = new ScientificAwardCheck();
list.accept(sac);
eac = new ExcellenceAwardCheck();
list.accept(eac);
}
}
在以下情况下可以使用访问者模式:
一个对象结构包含很多类型的对象,希望对这些对象实施一些依赖其具体类型的操作。在访问者中针对每一种具体的类型都提供了一个访问操作,不同类型的对象可以有不同的访问操作。
需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作“污染”这些对象的类,也不希望在增加新操作时修改这些类。访问者模式使得我们可以将相关的访问操作集中起来定义在访问者类中,对象结构可以被多个不同的访问者类所使用,将对象本身与对象的访问操作分离。
对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作。
(1) 在一些编译器的设计中运用了访问者模式,程序代码是被访问的对象,它包括变量定义、变量赋值、逻辑运算、算术运算等语句,编译器需要对代码进行分析,如检查变量是否定义、变量是否赋值、算术运算是否合法等,可以将不同的操作封装在不同的类中,如检查变量定义的类、检查变量赋值的类、检查算术运算是否合法的类,这些类就是具体访问者,可以访问程序代码中不同类型的语句。在编译过程中除了代码分析外,还包含代码优化、空间分配和代码生成等部分,也可以将每一个不同编译阶段的操作封装到了跟该阶段有关的一个访问者类中。
(2) 在常用的Java XML处理技术DOM4J中,可以通过访问者模式的方式来读取并解析XML文档,VisitorSupport是DOM4J提供的Visitor接口的默认适配器,具体访问者只需继承VisitorSupport类即可。
访问者模式表示一个作用于某对象结构中的各元素的操作,它使我们可以在不改变各元素的类的前提下定义作用于这些元素的新操作。访问者模式是一种对象行为型模式。
访问者模式包含五个角色:抽象访问者为对象结构类中每一个抽象元素类声明一个访问操作;具体访问者实现了每个由抽象访问者声明的操作,每一个操作用于访问对象结构中一种类型的元素;抽象元素一般是抽象类或者接口,它定义一个accept()方法,该方法以一个抽象访问者作为参数;具体元素实现了accept()方法,在其accept()中调用访问者的访问方法以便完成对一个元素的操作;对象结构是一个元素的集合,它用于存放元素对象,并且提供了遍历其内部元素的方法。
访问者模式中对象结构存储了不同类型的元素对象,以供不同访问者访问。访问者模式包括两个层次结构,一个是访问者层次结构,提供了抽象访问者和具体访问者,一个是元素层次结构,提供了抽象元素和具体元素。相同的访问者可以以不同的方式访问不同的元素,相同的元素可以接受不同访问者以不同访问方式访问。在访问者模式中,增加新的访问者无须修改原有系统,系统具有较好的可扩展性。
访问者模式的主要优点在于使得增加新的访问操作变得很容易,将有关元素对象的访问行为集中到一个访问者对象中,而不是分散到一个个的元素类中,还可以跨过类的等级结构访问属于不同的等级结构的元素类,让用户能够在不修改现有类层次结构的情况下,定义该类层次结构的操作;其主要缺点在于增加新的元素类很困难,而且在一定程度上破坏系统的封装性。
访问者模式适用情况包括:一个对象结构包含很多类型的对象,希望对这些对象实施一些依赖其具体类型的操作;需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作“污染”这些对象的类,也不希望在增加新操作时修改这些类;对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作。