访问者模式(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; /** * 访问者模式:操作复杂对象结构的艺术 * @author qbg */ 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、破坏封装。访问者模式常常迫使用户提供访问元素内部状态的公共操作,这可能破坏元素的封装性。
原文:http://blog.csdn.net/qbg19881206/article/details/19298889