访问者模式,重点在于访问者二字。说到访问,我们脑海中必定会想起新闻访谈,两个人面对面坐在一起。从字面上的意思理解:其实就相当于被访问者(某个公众人物)把访问者(记者)当成了外人,不想你随便动。你想要什么,我弄好之后给你(调用你的方法)。
01 什么是访问者模式?访问者模式的定义如下所示,说的是在不改变数据结构的提前下,定义新操作。
封装一些作用于某种数据结构中的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。
但在实际的应用中,我发现有些例子并不是如此。有些例子中并没有稳定的数据结构,而是稳定的算法。在树义看来,访问者模式是:把不变的固定起来,变化的开放出去。
我们举生活中一个例子来聊聊:某科学家接受记着访谈。我们都知道科学家接受访问,肯定是有流程上的限制的,不可能让你随便问。我们假设这个过程是:先问科学家的学校经历,再聊你的工作经历,最后聊你的科研成果。那么在这个过程中,固定的是什么东西呢?固定的是接受采访的流程。变化的是什么呢?变化的是不同的记者,针对学校经历,可能会提不同的问题。
根据我们之前的理解,访问者模式其实就是要把不变的东西固定起来,变化的开放出去。那么对于科学家接受访谈这个事情,我们可以这么将其抽象化。
首先,我们需要有一个 Visitor 类,这里定义了一些外部(记者)可以做的事情(提学校经历、工作经历、科研成就的问题)。
public interface Visitor { public void askSchoolExperience(String name); public void askWorkExperience(String name); public void askScienceAchievement(String name); } 文章首发于个人博客 shuyi.tech,欢迎访问更多有趣有价值的文章。接着声明一个 XinhuaVisitor 类去实现 Visitor 类,这表示是新华社的一个记者(访问者)想去访问科学家。
public class XinhuaVisitor implements Visitor{ @Override public void askSchoolExperience(String name) { System.out.printf("请问%s:在学校取得的最大成就是什么?\n", name); } @Override public void askWorkExperience(String name) { System.out.printf("请问%s:工作上最难忘的事情是什么?\n", name); } @Override public void askScienceAchievement(String name) { System.out.printf("请问%s:最大的科研成果是什么?", name); } }接着声明一个 Scientist 类,表明是一个科学家。科学家通过一个 accept() 方法接收记者(访问者)的访问申请,将其存储起来。科学家定义了一个 interview 方法,将访问的流程固定死了,只有教你问什么的时候,我才会让你(记者)提问。
public class Scientist { private Visitor visitor; private String name; private Scientist(){} public Scientist(String name) { this.name = name; } public void accept(Visitor visitor) { this.visitor = visitor; } public void interview(){ System.out.println("------------访问开始------------"); System.out.println("---开始聊学校经历---"); visitor.askSchoolExperience(name); System.out.println("---开始聊工作经历---"); visitor.askWorkExperience(name); System.out.println("---开始聊科研成果---"); visitor.askScienceAchievement(name); } }最后我们声明一个场景类 Client,来模拟访谈这一过程。
public class Client { public static void main(String[] args) { Scientist yang = new Scientist("杨振宁"); yang.accept(new XinhuaVisitor()); yang.interview(); } }运行的结果为:
------------访问开始------------ ---开始聊学校经历--- 请问杨振宁:在学校取得的最大成就是什么? ---开始聊工作经历--- 请问杨振宁:工作上最难忘的意见事情是什么? ---开始聊科研成果--- 请问杨振宁:最大的科研成果是什么?看到这里,大家对于访问者模式的本质有了更感性的认识(把不变的固定起来,变化的开放出去)。在这个例子中,不变的固定的就是访谈流程,变化的就是你可以提不同的问题。
一般来说,访问者模式的类结构如下图所示:
Visitor 访问者接口。访问者接口定义了访问者可以做的事情。这个需要你去分析哪些是可变的,将这些可变的内容抽象成访问者接口的方法,开放出去。而被访问者的信息,其实就是通过访问者的参数传递过去。
ConcreteVisitor 具体访问者。具体访问者定义了具体某一类访问者的实现。对于新华社记者来说,他们更关心杨振宁科学成果方面的事情,于是他们提问的时候更倾向于挖掘成果。但对于青年报记者来说,他们的读者是青少年,他们更关心杨振宁在学习、工作中的那种精神。