访问者模式
一、问题引入
校长和院长检查教师和学生
校长和院长检查教师的工作情况和学生的学习情况;校长关注教师的教学工作量,学生学习的课程;院长关注教师的课程,学生的学习成绩。
由于校长和院长对于教师和学生的关注点是不一样的,这就需要对教师和学生进行不同的处理。
package operation;
import java.util.ArrayList;
import java.util.List;
abstract class Person{
private String name;
public Person(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class Teacher extends Person{
private String course;
private int amount;
public Teacher(String name, String course, int amount) {
super(name);
this.course = course;
this.amount = amount;
}
public String getCourse() {
return course;
}
public int getAmount() {
return amount;
}
}
class Student extends Person{
private String course;
private int grade;
public Student(String name, String course, int grade) {
super(name);
this.course = course;
this.grade = grade;
}
public String getCourse() {
return course;
}
public int getGrade() {
return grade;
}
}
class PresidentVisitor{
public void visit(Person person) {
if(person instanceof Teacher) {
Teacher teacher=(Teacher)person;
System.out.println("校长 访问老师 "+teacher.getName()+"学时:"+teacher.getAmount());
}else if(person instanceof Student) {
Student student=(Student)person;
System.out.println("校长 访问学生 "+student.getName()+"课程:"+student.getCourse());
}
}
}
class DeanVisitor{
public void visit(Person person) {
if(person instanceof Teacher) {
Teacher teacher=(Teacher)person;
System.out.println("院长 访问老师 "+teacher.getName()+"课程:"+teacher.getCourse());
}else if(person instanceof Student) {
Student student=(Student)person;
System.out.println("院长 访问学生 "+student.getName()+"成绩:"+student.getGrade());
}
}
}
public class Main{
public static void main(String[] args){
List<Person>listperson=new ArrayList<Person>();
Person t1=new Teacher("张老师","编译原理",48);
Person t2=new Teacher("王老师","数据库",54);
Student s1=new Student("赵同学","编译原理",90);
Student s2=new Student("刘同学","数据库",82);
listperson.add(t1);listperson.add(t2);
listperson.add(s1);listperson.add(s2);
PresidentVisitor pv=new PresidentVisitor();
for(Person b:listperson) {
pv.visit(b);
}
DeanVisitor dv=new DeanVisitor();
for(Person b:listperson) {
dv.visit(b);
}
}
}
运行结果:
校长 访问老师 张老师学时:48
校长 访问老师 王老师学时:54
校长 访问学生 赵同学课程:编译原理
校长 访问学生 刘同学课程:数据库
院长 访问老师 张老师课程:编译原理
院长 访问老师 王老师课程:数据库
院长 访问学生 赵同学成绩:90
院长 访问学生 刘同学成绩:82
改进:发现类PresidentVisitor和DeanVisitor有相同的方法visit,就可以提出一个接口Visitor,它含有抽象方法visit(),类PresidentVisitor和DeanVisitor实现它并实现其中的visit方法。
package operation;
import java.util.ArrayList;
import java.util.List;
abstract class Person{
private String name;
public Person(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class Teacher extends Person{
private String course;
private int amount;
public Teacher(String name, String course, int amount) {
super(name);
this.course = course;
this.amount = amount;
}
public String getCourse() {
return course;
}
public int getAmount() {
return amount;
}
}
class Student extends Person{
private String course;
private int grade;
public Student(String name, String course, int grade) {
super(name);
this.course = course;
this.grade = grade;
}
public String getCourse() {
return course;
}
public int getGrade() {
return grade;
}
}
interface Visitor{
abstract void visit(Person person);
}
class PresidentVisitor implements Visitor{
public void visit(Person person) {
if(person instanceof Teacher) {
Teacher teacher=(Teacher)person;
System.out.println("校长 访问老师 "+teacher.getName()+"学时:"+teacher.getAmount());
}else if(person instanceof Student) {
Student student=(Student)person;
System.out.println("校长 访问学生 "+student.getName()+"课程:"+student.getCourse());
}
}
}
class DeanVisitor implements Visitor{
public void visit(Person person) {
if(person instanceof Teacher) {
Teacher teacher=(Teacher)person;
System.out.println("院长 访问老师 "+teacher.getName()+"课程:"+teacher.getCourse());
}else if(person instanceof Student) {
Student student=(Student)person;
System.out.println("院长 访问学生 "+student.getName()+"成绩:"+student.getGrade());
}
}
}
public class Main{
public static void main(String[] args){
List<Person>listperson=new ArrayList<Person>();
Person t1=new Teacher("张老师","编译原理",48);
Person t2=new Teacher("王老师","数据库",54);
Student s1=new Student("赵同学","编译原理",90);
Student s2=new Student("刘同学","数据库",82);
listperson.add(t1);listperson.add(t2);
listperson.add(s1);listperson.add(s2);
Visitor pv=new PresidentVisitor();
for(Person b:listperson) {
pv.visit(b);
}
Visitor dv=new DeanVisitor();
for(Person b:listperson) {
dv.visit(b);
}
}
}
运行结果:
校长 访问老师 张老师学时:48
校长 访问老师 王老师学时:54
校长 访问学生 赵同学课程:编译原理
校长 访问学生 刘同学课程:数据库
院长 访问老师 张老师课程:编译原理
院长 访问老师 王老师课程:数据库
院长 访问学生 赵同学成绩:90
院长 访问学生 刘同学成绩:82
改进:Visitor中定义visit为重载函数,声明两个visit方法,参数分别是Teacher和Student.对于Teacher.、Student的访问会调用两个不同的方法,以此达成区别对待、差异化处理。
package operation;
import java.util.ArrayList;
import java.util.List;
abstract class Person{
private String name;
public Person(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class Teacher extends Person{
private String course;
private int amount;
public Teacher(String name, String course, int amount) {
super(name);
this.course = course;
this.amount = amount;
}
public String getCourse() {
return course;
}
public int getAmount() {
return amount;
}
}
class Student extends Person{
private String course;
private int grade;
public Student(String name, String course, int grade) {
super(name);
this.course = course;
this.grade = grade;
}
public String getCourse() {
return course;
}
public int getGrade() {
return grade;
}
}
interface Visitor{
void visit(Teacher teacher);
void visit(Student student);
}
class PresidentVisitor implements Visitor{
public void visit(Teacher teacher) {
System.out.println("校长 访问老师 "+teacher.getName()+"学时:"+teacher.getAmount());
}
public void visit(Student student) {
System.out.println("校长 访问学生 "+student.getName()+"课程:"+student.getCourse());
}
}
class DeanVisitor implements Visitor{
public void visit(Teacher teacher) {
System.out.println("院长 访问老师 "+teacher.getName()+"课程:"+teacher.getCourse());
}
public void visit(Student student) {
System.out.println("院长 访问学生 "+student.getName()+"成绩:"+student.getGrade());
}
}
public class Main{
public static void main(String[] args){
List<Person>listperson=new ArrayList<Person>();
Person t1=new Teacher("张老师","编译原理",48);
Person t2=new Teacher("王老师","数据库",54);
Person s1=new Student("赵同学","编译原理",90);
Person s2=new Student("刘同学","数据库",82);
listperson.add(t1);listperson.add(t2);
listperson.add(s1);listperson.add(s2);
Visitor pv=new PresidentVisitor();
for(Person b:listperson) {
if(b instanceof Teacher) {
Teacher teacher=(Teacher)b;
pv.visit(teacher);
}else if(b instanceof Student) {
Student student=(Student)b;
pv.visit(student);
}
}
Visitor dv=new DeanVisitor();
for(Person b:listperson) {
if(b instanceof Teacher) {
Teacher teacher=(Teacher)b;
dv.visit(teacher);
}else if(b instanceof Student) {
Student student=(Student)b;
dv.visit(student);
}
}
}
}
校长 访问老师 张老师学时:48
校长 访问老师 王老师学时:54
校长 访问学生 赵同学课程:编译原理
校长 访问学生 刘同学课程:数据库
院长 访问老师 张老师课程:编译原理
院长 访问老师 王老师课程:数据库
院长 访问学生 赵同学成绩:90
院长 访问学生 刘同学成绩:82
问题:把判断转移到了客户端,这种public void visit(Teacher teacher)或public void visit(Student student)访问是由校长或院长发起调用的,所以调用时必需指明参数具体是老师还是学生。
改进:如果在老师和学生类定义方法accept ( Visitor visitor )接受校长或院长访问,在方法实现时通过:visitor.visit(this),当前老师或学生作为实参传逆,就去除了判断。
package operation;
import java.util.ArrayList;
import java.util.List;
abstract class Person{
private String name;
public Person(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public abstract void accept(Visitor visitor);
}
class Teacher extends Person{
private String course;
private int amount;
public Teacher(String name, String course, int amount) {
super(name);
this.course = course;
this.amount = amount;
}
public String getCourse() {
return course;
}
public int getAmount() {
return amount;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
class Student extends Person{
private String course;
private int grade;
public Student(String name, String course, int grade) {
super(name);
this.course = course;
this.grade = grade;
}
public String getCourse() {
return course;
}
public int getGrade() {
return grade;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
interface Visitor{
void visit(Teacher teacher);
void visit(Student student);
}
class PresidentVisitor implements Visitor{
public void visit(Teacher teacher) {
System.out.println("校长 访问老师 "+teacher.getName()+"学时:"+teacher.getAmount());
}
public void visit(Student student) {
System.out.println("校长 访问学生 "+student.getName()+"课程:"+student.getCourse());
}
}
class DeanVisitor implements Visitor{
public void visit(Teacher teacher) {
System.out.println("院长 访问老师 "+teacher.getName()+"课程:"+teacher.getCourse());
}
public void visit(Student student) {
System.out.println("院长 访问学生 "+student.getName()+"成绩:"+student.getGrade());
}
}
class ObjectList{
private List<Person>lists=new ArrayList<Person>();
public void Attach(Person element) {
lists.add(element);
}
public void Detach(Person element) {
lists.remove(element);
}
public void Display(Visitor visitor) {
for(Person element:lists) {
element.accept(visitor);
}
}
}
public class Main{
public static void main(String[] args){
Person t1=new Teacher("张老师","编译原理",48);
Person t2=new Teacher("王老师","数据库",54);
Person s1=new Student("赵同学","编译原理",90);
Person s2=new Student("刘同学","数据库",82);
Visitor p=new PresidentVisitor();
Visitor d=new DeanVisitor();
ObjectList listperson=new ObjectList();
listperson.Attach(t1);
listperson.Attach(t2);
listperson.Attach(s1);
listperson.Attach(s2);
listperson.Display(p);
System.out.println("=============================");
listperson.Display(d);
}
}
运行结果:
校长 访问老师 张老师学时:48
校长 访问老师 王老师学时:54
校长 访问学生 赵同学课程:编译原理
校长 访问学生 刘同学课程:数据库
=============================
院长 访问老师 张老师课程:编译原理
院长 访问老师 王老师课程:数据库
院长 访问学生 赵同学成绩:90
院长 访问学生 刘同学成绩:82
二、访问者模式
package operation;
import java.util.ArrayList;
import java.util.List;
abstract class Element{
public abstract void Accept(Visitor visitor);
}
class ConcreteElementA extends Element{
public void Accept(Visitor visitor) {
visitor.VisitConcreteElementA(this);
}
public void OperationA() {}
}
class ConcreteElementB extends Element{
public void Accept(Visitor visitor) {
visitor.VisitConcreteElementB(this);
}
public void OperationB() {}
}
abstract class Visitor{
public abstract void VisitConcreteElementA(ConcreteElementA concreteElementA);
public abstract void VisitConcreteElementB(ConcreteElementB concreteElementB);
}
class ConcreteVisitor1 extends Visitor{
public void VisitConcreteElementA(ConcreteElementA concreteElementA) {
System.out.println(concreteElementA.getClass().toString()+"被"+this.getClass().toString()+"访问");
}
public void VisitConcreteElementB(ConcreteElementB concreteElementB) {
System.out.println(concreteElementB.getClass().toString()+"被"+this.getClass().toString()+"访问");
}
}
class ConcreteVisitor2 extends Visitor{
public void VisitConcreteElementA(ConcreteElementA concreteElementA) {
System.out.println(concreteElementA.getClass().toString()+"被"+this.getClass().toString()+"访问");
}
public void VisitConcreteElementB(ConcreteElementB concreteElementB) {
System.out.println(concreteElementB.getClass().toString()+"被"+this.getClass().toString()+"访问");
}
}
class ObjectStructure{
private List<Element>elements=new ArrayList<Element>();
public void Attach(Element element) {
elements.add(element);
}
public void Detach(Element element) {
elements.remove(element);
}
public void Accept(Visitor visitor) {
for(Element e:elements) {
e.Accept(visitor);
}
}
}
public class Main{
public static void main(String[] args){
ObjectStructure o=new ObjectStructure();
o.Attach(new ConcreteElementA());
o.Attach(new ConcreteElementB());
ConcreteVisitor1 v1=new ConcreteVisitor1();
ConcreteVisitor2 v2=new ConcreteVisitor2();
o.Accept(v1);
o.Accept(v2);
}
}
三、访问者模式优缺点
优点:
1、符合单一职责原则。
2、优秀的扩展性。
3、灵活性。
缺点:
1、具体元素对访问者公布细节,违反了迪米特原则。
2、具体元素变更比较困难。
3、违反了依赖倒置原则,依赖了具体类,没有依赖抽象。