访问者模式
定义:封装了一些作用于某种数据结构中得各元素得操作,它可以再不改变这个数据结构得前提下定义作用于这些元素得新得操作
访问者模式主要结构如下:
抽象访问者角色:定义了对每一个元素的访问的行为,它的参数就是可以访问的参数,它的方法个数理论上来讲与元素个数(抽象元素类子实现类的个数)是一样的,从这点不难看出,访问者模式要求元素类的个数不能改变
具体访问者角色:给出对每个元素类访问时所产生的具体的行为
抽象元素角色:定义了一个接收访问者的方法,其意义是指,每一个元素都可以被访问者访问
具体元素角色:提供接收访问方法的具体实现,而这个具体的实现,通常情况下是使用访问者提供的访问该元素类的方法
对象结构角色:对象结构是一个抽象的表达,具体点可以理解为一个具有容器性质或者复合对象特性的类,它会含有一组元素,并且可以迭代这些元素,供访问者访问
案例实现
学校中有老师,有学生,对于校长来说,校长只关注学生的姓名和性别,老师的姓名以及所带班级的升学率。对于家长来说,只关注学生的姓名和在校成绩排名,关注老师的姓名和年龄。针对不同的访问者(校长,家长),能够提供不同的数据供他们查阅。再本例中,学校相当于对象结构角色,而家长和校长则相当于具体访问者角色,其中学生和教师则是具体元素角色
代码实现:
定义抽象访问者,其中方法个数和具体元素类的个数一样多
public interface Visitor { String visitStudent(StudentElement element); String visitTeacher(TeacherElement element); }
定义具体访问者校长
public class HeadmasterVisitor implements Visitor{ /** * 校长访问学生之关注姓名和性别 * @param element 具体元素,学生 * @return 返回校长所关注的学生信息 */ @Override public String visitStudent(StudentElement element) { Map<String,Object> info=new HashMap<>(2); info.put("学生姓名",element.getName()); info.put("学生性别",element.getSex()); return JSON.toJSONString(info); } /** * 校长访问教师信息,只在乎教师的姓名和所带班级的升学率 * @param element 具体元素,教师 * @return 返回校长所关注的教师的信息 */ @Override public String visitTeacher(TeacherElement element) { Map<String,Object> info=new HashMap<>(2); info.put("教师姓名",element.getName()); info.put("升学率",element.getStudy()); return JSON.toJSONString(info); } }
定义具体访问者家长
public class ParentsVisitor implements Visitor{ /** * 家长访问学生信息,只关注学生姓名和排名 * @param element 具体元素,学生 * @return 返回家长所关注的学生信息 */ @Override public String visitStudent(StudentElement element) { Map<String,Object> info=new HashMap<>(2); info.put("学生姓名",element.getName()); info.put("学生排名",element.getRanking()); return JSON.toJSONString(info); } /** * 家长访问教师,只在乎教师的姓名和年龄 * @param element 具体元素,教师 * @return 返回家长所关注的教师的信息 */ @Override public String visitTeacher(TeacherElement element) { Map<String,Object> info=new HashMap<>(2); info.put("教师姓名",element.getName()); info.put("教师年龄",element.getAge()); return JSON.toJSONString(info); } }
定义抽象元素角色
public interface Element { void accept(Visitor visitor); }
定义具体元素角色学生
public class StudentElement implements Element{ private String name; private String sex; private Integer ranking; public StudentElement(String name,String sex){ this.name=name; this.sex=sex; this.ranking=(int) (Math.random()*100); } @Override public void accept(Visitor visitor) { System.out.println(visitor.visitStudent(this)); } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public Integer getRanking() { return ranking; } public void setRanking(Integer ranking) { this.ranking = ranking; } }
定义具体元素角色教师
public class TeacherElement implements Element{ private String name; private Integer age; private String study; public TeacherElement(String name,Integer age){ this.name=name; this.age=age; this.study=((int) (Math.random()*100))+"%"; } @Override public void accept(Visitor visitor) { System.out.println(visitor.visitTeacher(this)); } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getStudy() { return study; } public void setStudy(String study) { this.study = study; } }
定义对象结构角色(学校)
public class ObjectStructure { private final List<Element> elementList=new ArrayList<>(); public ObjectStructure(){ //初始化学生 StudentElement studentElement1=new StudentElement("学生1","男"); StudentElement studentElement2=new StudentElement("学生2","男"); StudentElement studentElement3=new StudentElement("学生3","男"); //初始化教师 TeacherElement teacherElement1=new TeacherElement("教师1",25); TeacherElement teacherElement2=new TeacherElement("教师2",25); TeacherElement teacherElement3=new TeacherElement("教师3",25); //添加学生信息 elementList.add(studentElement1); elementList.add(studentElement2); elementList.add(studentElement3); //添加教师信息 elementList.add(teacherElement1); elementList.add(teacherElement2); elementList.add(teacherElement3); } /** * 提供显示功能,根据不同的访问者,显示对应的访问者所关注的信息 * @param visitor 访问者,可以是校长,可以是家长 */ public void show(Visitor visitor){ elementList.forEach(element -> {element.accept(visitor);}); } }
定义测试类测试访问者模式
public class Test { public static void main(String[] args) { ObjectStructure objectStructure=new ObjectStructure(); System.out.println("==================家长看板================="); objectStructure.show(new ParentsVisitor()); System.out.println("==================校长看板================="); objectStructure.show(new HeadmasterVisitor()); } }
访问者模式优缺点
优点
扩展性好,再不修改对象结构中元素的情况下,为对象结构中的元素添加新的功能
复用性好,通过访问者来定义整个对象结构通用的功能,从而提高复用程度
分离无关行为,通过访问者来分离无关的行为,把相关的行为封装再一起,构成访问者,这样每一个访问者的功能都比较单一
缺点
对象结构变化很困难,再访问者模式中,每增加一个新的元素类,都要再每一个具体访问者中增加相应的具体操作,者违背了开闭原则
违反了依赖倒置原则,访问者模式中依赖某个具体类,而没有依赖抽象类
访问者模式应用场景
对象结构相对稳定,但其操作算法经常变化的程序
对象结构中的对象需要提供多种不同且不相关的操作,而且要避免让这些操作的变化影响对象的结构
希望这篇文章对您有帮助,同时也希望您在闲暇之余能够帮忙使用微信扫一下下面的小程序二维码帮忙助力一下小程序的访问量,谢谢