访问者模式(VISITOR),提供一个作用于某对象结构中各元素的操作表示,并使我们可以在不改变各元素的类的前提下定义作用于这些元素的新操作,属于对象行为型模式。使用Visitor模式,必须定义两个类层次:一个对应于接受操作的元素(Element层次),另一个对应于定义对元素的操作的访问者(Visitor层次)。给访问者类层次增加一个新的子类即可创建一个新的操作,但如果新增一个接受操作的元素,则需要修改Visitor及其子类实现,这是Visitor模式的最大缺点。Visitor模式在XML文档解析,编译器设计,复杂集合对象处理中得到一定的应用。
一、使用场景
1、对于一个包含很多具有不同接口的类对象的复杂对象结构,可以使用Visitor模式对它内部的类对象实施一些依赖于它们的具体类的操作。
2、需要对一个对象结构中的对象进行很多不同且不相关的操作,并要避免这些操作“污染”对象的类。Visitor模式使得我们可以将相关的访问操作集中起来定义在访问者类中,对象结构可以被多个不同的访问者类所使用,将对象本身与对象的访问操作分离。
3、定义对象结构的类(Element类层次)很少改变,但经常需要在此结构上定义新的操作。改变对象结构类需要重新定义对所有访问者的接口,代价很大。
二、UML图

三、Java实现
- package study.patterns.visitor;
-
- import java.util.ArrayList;
- import java.util.List;
-
-
-
-
- public class VisitorPattern {
- public static void main(String[] args) {
- StaffList staffList = new StaffList();
- Teacher t1 = new Teacher("张三", 12, 95);
- staffList.addStaff(t1);
- Teacher t2 = new Teacher("李四", 8, 85);
- staffList.addStaff(t2);
- Student s1 = new Student("王五", 0, 80);
- staffList.addStaff(s1);
- Student s2 = new Student("赵六", 3, 93);
- staffList.addStaff(s2);
- AwardCheck srAward = new ScientificResearchAward();
- System.out.println("=========评选科研奖===============");
- staffList.accept(srAward);
- System.out.println("=========评选优秀成绩奖===========");
- AwardCheck oaAward = new OutstandingAchievementAward();
- staffList.accept(oaAward);
- }
- }
-
-
-
- interface Staff{
- public void accept(AwardCheck handler);
- }
-
-
-
- class Teacher implements Staff{
- private String name;
- private int paperCount;
- private int feedBackScore;
-
- public Teacher(String name,int pagerCount,int feedBackScore){
- this.name = name;
- this.paperCount = pagerCount;
- this.feedBackScore = feedBackScore;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public int getPaperCount() {
- return paperCount;
- }
-
- public void setPaperCount(int paperCount) {
- this.paperCount = paperCount;
- }
-
- public int getFeedBackScore() {
- return feedBackScore;
- }
-
- public void setFeedBackScore(int feedBackScore) {
- this.feedBackScore = feedBackScore;
- }
-
- @Override
- public void accept(AwardCheck handler) {
- handler.visit(this);
- }
- }
-
-
-
- class Student implements Staff{
- private String name;
- private int paperCount;
- private int averageScore;
-
- public Student(String name,int paperCount,int averageScore){
- this.name = name;
- this.paperCount = paperCount;
- this.averageScore = averageScore;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public int getPaperCount() {
- return paperCount;
- }
-
- public void setPaPerCount(int paperCount) {
- this.paperCount = paperCount;
- }
-
- public int getAverageScore() {
- return averageScore;
- }
-
- public void setAverageScore(int averageScore) {
- this.averageScore = averageScore;
- }
-
- @Override
- public void accept(AwardCheck handler) {
- handler.visit(this);
- }
- }
-
-
-
- interface AwardCheck{
- public void visit(Teacher teacher);
- public void visit(Student student);
- }
-
-
-
- class ScientificResearchAward implements AwardCheck{
-
- @Override
- public void visit(Teacher teacher) {
- String result = teacher.getPaperCount()>10?"恭喜获取科研奖":"很遗憾未获取科研奖";
- System.out.println("教师:"+teacher.getName()+",发表论文数:"+teacher.getPaperCount()+","+result);
- }
-
- @Override
- public void visit(Student student) {
- String result = student.getPaperCount()>2?"恭喜获取科研奖":"很遗憾未获取科研奖";
- System.out.println("学生:"+student.getName()+",发表论文数:"+student.getPaperCount()+","+result);
- }
- }
-
-
-
- class OutstandingAchievementAward implements AwardCheck{
-
- @Override
- public void visit(Teacher teacher) {
- String result = teacher.getFeedBackScore()>=90?"恭喜获取优秀成绩奖":"很遗憾未获取优秀成绩奖";
- System.out.println("教师:"+teacher.getName()+",教学反馈分数:"+teacher.getFeedBackScore()+","+result);
- }
-
- @Override
- public void visit(Student student) {
- String result = student.getAverageScore()>=90?"恭喜获取优秀成绩奖":"很遗憾未获取优秀成绩奖";
- System.out.println("学生:"+student.getName()+",学科平均分数:"+student.getAverageScore()+","+result);
- }
-
- }
-
-
-
- class StaffList{
- private List<Staff> staffs = new ArrayList<Staff>();
-
- public void addStaff(Staff staff){
- staffs.add(staff);
- }
-
-
-
-
- public void accept(AwardCheck handler){
- for(Staff staff : staffs){
- staff.accept(handler);
- }
- }
- }
运行结果:
- =========评选科研奖===============
- 教师:张三,发表论文数:12,恭喜获取科研奖
- 教师:李四,发表论文数:8,很遗憾未获取科研奖
- 学生:王五,发表论文数:0,很遗憾未获取科研奖
- 学生:赵六,发表论文数:3,恭喜获取科研奖
- =========评选优秀成绩奖===========
- 教师:张三,教学反馈分数:95,恭喜获取优秀成绩奖
- 教师:李四,教学反馈分数:85,很遗憾未获取优秀成绩奖
- 学生:王五,学科平均分数:80,很遗憾未获取优秀成绩奖
- 学生:赵六,学科平均分数:93,恭喜获取优秀成绩奖
四、模式优缺点
优点:
1、访问者模式使得易于增加新的操作。仅需增加一个新的访问者即可在一个对象结构上定义一个新的操作。
2、访问者集中相关的操作而分离无关的操作。相关的行为集中在一个访问者中,无关的行为被分散到各自的访问者子类中。
3、让用户可以在不改变现有类层次结构的情况下,定义作用于该层次结构的操作。
4、累计状态。当访问者访问对象结构中的每一个元素时,可以积累状态,否则需要将状态作为额外的参数传递给进行遍历的操作,或定义为全局变量。
缺点:
1、增加新的ConcreteElement类很困难。增加新的元素类需要在Visitor中添加新的抽象操作,并在每一个ConcreteVisitor类中实现相应的操作,违背“开闭原则”。
2、破坏封装。访问者模式常常迫使用户提供访问元素内部状态的公共操作,这可能破坏元素的封装性。