1、概念
在不修改原始类结构的基础上,将原始类的某种功能委托给访问者类来实现。
它的核心思想是”duck-typing”,忽略原始类结构,抽象其公共的功能。
理解访问者模式的关键点,我认为有以下几点:
- 为什么原始类不能自己实现这种功能,一方面这个功能与类结构确实无关,例如序列化,另外一个方面这个功能有公共的步骤,例如迭代器可以被抽象为next,hasNext,这种功能通常是某些类的公共功能,如果因为实现此功能,而对所有类进行修改基本不可能。
- 原始类与访问者类之间的关系,如果是依赖关系,可以是构造器参数,方法返回值,方法参数,属性等等这些形式,如果是泛化关系,原始类需要实现访问者类的接口。
例如序列化,首先原始类实现Serializable接口,而后某种其他机制实现序列化功能。
迭代器模式只是访问者模式的一种特例,功能只有遍历功能。
策略模式中功能是由原始类提供,而将不同的实现方式委托给其他类。访问者模式中功能和实现方式都委托给其他类,还是存在一定的差异。
我感觉模仿Java实现迭代,比较这些功能的方式比较好,提供两个接口
- 第一个接口类似于Comparable,用于标识原始类是否拥有此功能。
- 第二个接口类似于Comparator,用于提供此功能的实现方式,不同实现类提供不同的实现方式。
2、UML图
3、代码
没有固定的类结构,此处省略。
4、讨论
以生活中的一个示例讨论一下,人---->交通工具。
首先人有很多种角度,可以分为男女,可以分为父亲,母亲,儿子,女儿等等。假设系统存在很多类,它们本质都是人的抽象,但是类型却不同,例如存在User类,Employee类,Customer类,此时需要添加一种公共的功能,远行(抽象的代表从一个地方移动到另外一个地点)。
设计Walkable(抽象的代表是否需要远行),例如Role类,它虽然是人的抽象,但是并不需要实现此接口。
所有的这些类都实现Walkable接口,设计具体的Transfer接口,它用于抽象代表人的移动方式,可以是跑,走,可以使用交通工具,自行车,摩托车,电动车,汽车,公交车,出租车,火车,飞机,地铁等等。
从上述理解访问者模式的两个关键问题,
问题1:为什么原始类不能自己实现远行功能?
答:第一原始类的基数较大,每个类都添加这个功能会很繁琐。第二这个功能与原始类的类型没有任何关系,只要它是人的抽象,便可以实现此功能。
假设原始类是有限的,每一个都实现了此功能,例如提供了walk(Transfer transfer)方法,此时它就是策略模式,由Transfer接口提供具体的交通方式。
问题2:原始类和委托类之间的关系?
答:可以是依赖关系,例如构造器方法,属性,方法返回值,方法参数等等,但是更好的方式是委托类使用泛型,其中泛型T抽象的代表原始类。而用Walkable表示泛型的上限。
5、示例
集合的排序,类的比较,类的序列化。它没有固定的格式,只要理解duck-typing这种思想即可。