设计模式学习笔记(40)——访问者模式及其实现

访问者模式
一、问题引入
校长和院长检查教师和学生
校长和院长检查教师的工作情况和学生的学习情况;校长关注教师的教学工作量,学生学习的课程;院长关注教师的课程,学生的学习成绩。
由于校长和院长对于教师和学生的关注点是不一样的,这就需要对教师和学生进行不同的处理。

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、违反了依赖倒置原则,依赖了具体类,没有依赖抽象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值