什么是访问者模式
官方的说:访问者模式( Visitor pattern),封装一些作用于某种数据结构的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。
你可能认为上面的这段介绍太过抽象了。简单点来说就是。在被访问的类里面加一个对外提供接待访问者的接口,来使将数据结构与数据操作分离,解决数据结构和操作耦合性问题。
主要应用场景是:对象结构比较稳定,但经常需要在此对象结构上定义新的操作。或者需要对一个数据结构中的对象进行很多不同操作
(这些操作彼此没有关联),同时需要避免让这些操作"污染"这些对象的类,可以选用访问者模式解决。
案例
疫情期间,为了加强管理,所有人进出学校需办理出入证才可进出学校,学生的出入证由辅导员办理,教职工的出入证由教务处办理,而外来人员的出入证则由保卫处办理,不能跨越部门办理出入证,请用访问者模式实现出入证的办理过程。
传统方案下的案例分析
想要学习一个设计模式,首要的就是了解这个设计模式解决什么。
在我们没有学习过访问者模式前我们可以采用继承的方法,把辅导员,教务处和保卫处都继承同一个父类,实现父类所定义的办理出入证的方法。从而实现案例。
传统方式的问题分析
- 当系统增加新的功能时,会大量的改动代码,一定违反了ocp原则。
- 拓展性不好。
访问者模式的UML类图
- Visitor:抽象访问者类,定义了对每个 Approve访问的行为,它的参数就是被访问的Approve子类,方法个数与元素的个数是一样的,要求元素的类型要稳定。
- Student,Teacher,Outsiders:具体的访问者,它需要给出对每一个元素类访问时所产生的具体操作。
- Approve:抽象的被访者类,它定义了一个接受访问者(accept)的方法,其意义是指每一个元素都要可以被访问者访问。
-Counselor,SecOffice,AAOffice:具体的被访者类,具体实现accept方法,accept是访问者提供的访问该元素类的方法。 - ObjectStructure:定义当中所提到的对象结构,对象结构是一个抽象表述,它内部管理了元素集合。
访问者模式的代码
抽象访问者类:Visitor 类,定义了对不同被访问者的行为
package visitorPattern;
public abstract class Visitor {
//得到辅导员的批准Counselor
public abstract void getCounselorApprove(Counselor counselor);
//得到教务处的批准Academic Affairs Office
public abstract void getAAOfficeApprove(AAOffice aAOffice);
//得到保卫处的批准Security Office
public abstract void getSecOfficeApprove(SecOffice secOffice);
}
Student,Teacher,Outsiders:具体的访问者,它需要给出对每一个元素类访问时所产生的具体操作。
package visitorPattern;
public class Student extends Visitor {
@Override
public void getCounselorApprove(Counselor counselor) {
// TODO Auto-generated method stub
System.out.println("你是学生");
System.out.println("辅导员可以批准你的申请");
}
@Override
public void getAAOfficeApprove(AAOffice aAOffice) {
// TODO Auto-generated method stub
}
@Override
public void getSecOfficeApprove(SecOffice secOffice) {
// TODO Auto-generated method stub
}
}
package visitorPattern;
public class Teacher extends Visitor {
@Override
public void getCounselorApprove(Counselor counselor) {
// TODO Auto-generated method stub
}
@Override
public void getAAOfficeApprove(AAOffice aAOffice) {
// TODO Auto-generated method stub
System.out.println("你是教师");
System.out.println("教务处可以批准你的申请");
}
@Override
public void getSecOfficeApprove(SecOffice secOffice) {
// TODO Auto-generated method stub
}
}
package visitorPattern;
public class Outsiders extends Visitor{
@Override
public void getCounselorApprove(Counselor counselor) {
// TODO Auto-generated method stub
}
@Override
public void getAAOfficeApprove(AAOffice aAOffice) {
// TODO Auto-generated method stub
}
@Override
public void getSecOfficeApprove(SecOffice secOffice) {
// TODO Auto-generated method stub
System.out.println("你是外来人员");
System.out.println("保卫处可以批准你的申请");
}
}
Approve:抽象的被访者类,它定义了一个接受访问者(accept)的方法,其意义是指每一个元素都要可以被访问者访问。
package visitorPattern;
//审批机构
public abstract class Approve {
//提供一个方法,让访问者访问
public abstract void accept(Visitor visitor);
}
Counselor,SecOffice,AAOffice:具体的被访者类,具体实现accept方法,accept是访问者提供的访问该元素类的方法。使用了双分派,所谓双分派是指不管类怎么变化,我们都能找到期望的方法运行,双分派意味着得到执行的操作取决于请求的种类和两个接收者的类型,由于使用了双分派,只需增加一个 Action子类即可在客户端调用。
package visitorPattern;
//辅导员
public class Counselor extends Approve {
@Override
public void accept(Visitor visitor) {
// TODO Auto-generated method stub
visitor.getCounselorApprove(this);
}
}
package visitorPattern;
//教务处Academic Affairs Office
public class AAOffice extends Approve {
@Override
public void accept(Visitor visitor) {
// TODO Auto-generated method stub
visitor.getAAOfficeApprove(this);
}
}
package visitorPattern;
//保卫处Security Office
public class SecOffice extends Approve{
@Override
public void accept(Visitor visitor) {
// TODO Auto-generated method stub
visitor.getSecOfficeApprove(this);
}
}
ObjectStructure:定义当中所提到的对象结构,对象结构是一个抽象表述,它内部管理了元素集合。
package visitorPattern;
import java.util.LinkedList;
import java.util.List;
//建立一个数据结构去管理审批机构
public class ObjectStructure {
private List<Approve> approves=new LinkedList<>();
//增加
public void attach(Approve approve) {
approves.add(approve);
}
//移除
public void detach(Approve approve) {
approves.remove(approve);
}
//显示
public void display(Visitor visitor) {
for (Approve approve: approves) {
approve.accept(visitor);
}
}
}
客户端
package visitorPattern;
public class Client {
public static void main(String[] args) {
// TODO Auto-generated method stub
ObjectStructure objectStructure = new ObjectStructure();
objectStructure.attach(new Counselor());
objectStructure.attach(new AAOffice());
objectStructure.attach(new SecOffice());
// 学生
Student student = new Student();
objectStructure.display(student);
System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
// 教师
Teacher teacher = new Teacher();
objectStructure.display(teacher);
System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
// 外来人员
Outsiders outsiders = new Outsiders();
objectStructure.display(outsiders);
}
}
总结
-
访问者模式符合单一职责原则、让程序具有优秀的扩展性、灵活性非常高。
-
访问者模式适用于数据结构相对稳定的系统,可以对功能进行统一。如果一个系统有比较稳定的数据结构,又有经常变化的功能需求,那么访问者模式就是比较合适的
-
具体元素对访问者公布细节,违反了迪米特法则。
-
违背了依赖倒转原则。访问者依赖的是具体元素,而不是抽象元素。
喜欢这篇文章的给点一个赞吧~