从零开始学习Java设计模式 | 行为型模式篇:访问者模式

Posted 李阿昀

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从零开始学习Java设计模式 | 行为型模式篇:访问者模式相关的知识,希望对你有一定的参考价值。

在本讲,我们来学习一下行为型模式里面的第九个设计模式,即访问者模式。

概述

先来看一下访问者模式的概念。

封装一些作用于某种数据结构中的各元素的操作,它可以在不改变这个数据结构的前提下定义作用于这些元素的新的操作。

上述访问者模式的概念看完之后,相信大家都懵了,没关系,下面我给大家解释解释。

访问者模式是说封装一些作用于某种数据结构中的各元素的操作,这句话表示什么含义呢?其实就是说将数据结构和元素的操作进行了一个分离,分离之后,访问者模式就可以在不改变这个数据结构的前提下定义作用于这些元素的新的操作

可能我这样解释了之后,大家可能还不是特别理解,但没关系,后面我会通过一个案例再来对访问者模式进行一个讲解,相信大家一定能明白访问者模式的概念。

知道了访问者模式的概念之后,接下来,我们就来看看访问者模式的结构,也就是它里面所拥有的角色。

结构

访问者模式包含以下主要角色:

  • 抽象访问者(Visitor)角色:定义了对每一个元素(Element)访问的行为,它的参数就是可以访问的元素,它的方法个数理论上来讲与元素类个数(即Element抽象元素角色类的实现类的个数)是一样的,从这点不难看出,访问者模式要求元素类的个数不能改变。

    看完抽象访问者角色的概念,哎,你会发现概念中提到了元素这一东东,这不禁让我们想到了集合,因为集合里面存储的就是元素,所以在这儿必定会有一个容器性质的对象,这个留待我们后续再说。

    另外,我也不知道大家有没有看懂以上抽象访问者角色的概念,要是没看懂的话,我这里再来重新解释一遍。一般来说,我们会将抽象访问者角色定义成一个接口,然后在该接口中定义对每一个元素访问的方法,当然了,方法的参数就是可以访问的元素,所以有多少个具体元素角色类,那么该接口里面就要提供多少个方法。这也就是说,理论上讲,方法个数应与元素类个数(即Element抽象元素类的实现类的个数)是一样的,从这点不难看出,访问者模式要求元素类的个数不能改变,如果改变了的话,那么你就不能使用访问者模式了。所以,使用访问者模式的要求还是比较苛刻的,相信大家也不难看出访问者模式在实际开发中使用的其实并不是特别多!

  • 具体访问者(Concrete Visitor)角色:给出对每一个元素类访问时所产生的具体行为。说到底其实就是对抽象访问者角色里面方法的一个实现。

  • 抽象元素(Element)角色:定义了一个接受访问者的方法(即accept),其意义是指,每一个元素都要可以被访问者访问。注意了,该角色只是定义了一个规范,而该规范由谁来实现呢?由具体元素角色类来实现。

  • 具体元素(Concrete Element)角色:提供接受访问方法的具体实现,而这个具体的实现,通常情况下是使用访问者提供的访问该元素类的方法。

  • 对象结构(Object Structure)角色:定义当中所提到的对象结构(其实指的就是访问者模式概念里面所提到的数据结构),对象结构是一个抽象表述,具体点可以理解为一个具有容器性质或者复合对象特性的类,它会包含一组元素(Element),并且可以迭代这些元素,供访问者访问。

相信大家看完以上访问者模式所包含的角色之后,应该是一脸懵逼的😥,不过这没关系,下面我会通过一个具体的案例来让大家再深入认识一下以上访问者模式的五个角色。

访问者模式案例

接下来,按照惯例我们通过一个案例来让大家再去理解一下访问者模式的概念,以及它里面所包含的角色,而这个案例就是给宠物喂食。

分析

现在养宠物的人特别多,我们就以这个为例,当然宠物还分为狗、猫等,要给宠物喂食的话,不仅主人可以喂,其他人也是可以进行喂食的。

接下来,我们就来分析一下访问者模式里面的各个角色在该案例中分别是由谁来充当的。

  • 抽象访问者角色:给宠物喂食的人。
  • 具体访问者角色:主人、其他人。
  • 抽象元素角色:动物抽象类。
  • 具体元素角色:宠物狗、宠物猫。
  • 结构对象角色:主人家。

分析完之后,我们就来看一下下面这张类图。

看完以上类图之后,接下来我们就要逐一分析以上类图中所涉及到的类和接口,以及类和类、类和接口之间的关系了。

首先,我们先来看一下以上类图的左侧部分,可以看到上面有一个接口,名称为Animal,很显然,该接口充当的就是访问者模式里面的抽象元素角色。而且,该接口里面还提供了一个accept方法,很明显,该方法就是用来接受访问者访问的。不过大家要注意了,该方法还须接收一个Person类型的参数,而Person就是一个接口,这在类图的右侧部分就能看到,后面我再来讲解该接口啊!

对于Animal接口来说,它有两个子实现类,一个是Dog(即宠物狗类),一个是Cat(即宠物猫类),显然它俩都得实现Animal接口并重写里面的accept抽象方法,注意,它俩充当的是访问者模式里面的具体元素角色。

然后,我们再来看一下以上类图的右侧部分,可以看到上面也有一个接口,名称为Person,很显然,该接口充当的就是访问者模式里面的抽象访问者角色。而且,该接口里面还提供了两个feed方法,之前我在给大家讲述抽象访问者角色时就说过,对于它里面的方法来说,方法的个数以及参数是有一定特点的,方法个数的话,是和抽象元素角色类的子实现类的个数保持一致的,很明显,现在有两个子实现类,所以在Person接口里面我们就得提供两个feed方法;方法参数的话,就是具体元素角色类,即Cat和Dog,从上图中你也能清晰地看到。我之所以给大家解释的这么详细,就是希望大家能记住抽象访问者角色里面方法的以上特点。

对于Person接口来说,它也有两个子实现类,一个是Owner(即主人类),一个是Someone(即其他人类),显然它俩都得实现Person接口并重写里面的feed抽象方法,注意,它俩充当的是访问者模式里面的具体访问者角色。

接着,我们再来看一下Home这个类,很显然,它充当的就是访问者模式里面的对象结构角色。可以看到,该类里面声明了一个List<Animal>类型的成员变量,也就是说该成员变量就是一个List集合,而且List集合里面存储的元素类型是Animal,所以,大家可以把该类看作是一个容器。

此外,Home这个类里面还定义了两个方法,一个是add方法,它是往上述List集合里面去添加元素的,而且元素是Animal接口类型的;还有一个是action方法,它是来接受访问者访问的,访问谁呢?访问的就是List集合里面的元素。

最后,还有一个客户端类,该类就是用来做测试的,比较简单,所以这里我就不费多的笔墨去讲它了。

至此,以上类图我们就分析完了,接下来我们就要编写代码来实现以上给宠物喂食的案例了。

实现

。。。

以上是关于从零开始学习Java设计模式 | 行为型模式篇:访问者模式的主要内容,如果未能解决你的问题,请参考以下文章

从零开始学习Java设计模式 | 行为型模式篇:状态模式

从零开始学习Java设计模式 | 行为型模式篇:状态模式

从零开始学习Java设计模式 | 行为型模式篇:命令模式

从零开始学习Java设计模式 | 行为型模式篇:命令模式

从零开始学习Java设计模式 | 行为型模式篇:责任链模式

从零开始学习Java设计模式 | 行为型模式篇:责任链模式