访问者模式是对象的行为模式。访问者模式的目的是封装施加在某种数据结构元素上的操作。一旦一些操作需要修改,接受这个操作的数据结构可以保持不变。

个人觉得访问者模式相对其他的设计模式来说稍微复杂,难理解一点,要理解这个模式首先需要了解“单分派与多分派”。

单分派与多分派

根据对象的类型对执行方法进行选择,就是分派(Dispatch)。分派是面向对象语言提供的关键特性之一,根据分派发生的时期,可分为两种,静态分派和动态分派。静态分派发生在编译时期,动态分派发生在执行时期。

重载方法的分派是根据静态类型进行的,分派过程发生在编译时期,属于静态分派。

Java通过Override重写来支持动态分派,Java编译器并不会知道执行阶段会执行哪段重写的方法。

Java语言支持静态的多分派和动态的单分派,分别是通过重载方法和重写方式实现的。

Java语言通过两个宗量来决定执行哪一段代码:

方法的接受者:也即方法执行的对象,方法的接受者,动态分派根据具体类型决定;

事件对象:一个类行为的对象,传输的参数类型。

而访问者模式就是通过重写和重载的结合使用来达到实现双重分派的目的。

访问者模式

下面结合我们实际项目中的需求来阐述一下访问者模式。

访问者模式的类图如下:

所涉及到的角色:

抽象访问者:声明一个或多个访问操作,形成所有的具体元素角色必须实现的接口。下面的示例就是资源访问操作的顶层接口。

public interface IResourceVisitor {

	//detail resource

	void visit(JavaClassResource resource) throws ResourceParserException;

	void visit(MetadataResource resource) throws ResourceParserException;

	void visit(UpmResource resource) throws ResourceParserException;

	void visit(XmlResource resource) throws ResourceParserException;

	void visit(PropertiesResource propertiesResource) throws ResourceParserException;

	//composite resource

	void visit(BusinessComponentResource resource) throws ResourceParserException;

	void visit(JavaClassSrcResource resource) throws ResourceParserException;

具体访问者:实现抽象访问者角色所声明的接口,就是抽象访问所声明的各个访问操作。一般情况下,由于一般情况下抽象访问者的方法都比较多,而且具体访问者也不会关心抽象访问者的所有方法,因此通常有一个默认的实现Adaptor介于两者之间。

Adaptor也是一个非常重要的类,对于Composite类型的资源,存在一个默认遍历策略。

public abstract class AbstractResourceVisitorAdaptor implements IResourceVisitor {

	@Override
public void visit(JavaClassResource resource) throws ResourceParserException {
} @Override
public void visit(MetadataResource resource) throws ResourceParserException {
} @Override
public void visit(UpmResource resource) throws ResourceParserException {
} @Override
public void visit(XmlResource resource) throws ResourceParserException {
} @Override
public void visit(PropertiesResource propertiesResource) throws ResourceParserException {
} @Override
public final void visit(BusinessComponentResource resource) throws ResourceParserException {
visitComposite(resource);
} protected final void visitComposite(CompositeResource compositeResource) throws ResourceParserException {
List<IResource> subResources = compositeResource.getSubResources();
for (IResource subResource : subResources) {
subResource.accept(this);
}
}
}

抽象节点:声明一个接受操作,接受一个访问者对象作为一个参量。

public interface IResource {

	/**
* Visitor mode to access resources.
*
* @param resourceVisitor
*/
void accept(IResourceVisitor resourceVisitor) throws ResourceParserException; }

具体节点:实现抽象元素规定的accept操作,通常这个接口的层次结构反映了整个程序的数据结构。

结构对象: 结构对象可以遍历结构中的所有元素,如果需要,提供一个高层次的接口让访问者对象能够访问每一个元素;如果需要,可以设计成复合对象或一个聚集。

最终的UML类图结构如下所示(已隐藏过多的实现):

使用场景

访问者模式提供了一种倾斜的可扩展性,仅在当被访问的类结构非常稳定的时候使用(就比如PMD的类库中对Java代码结构进行了分析,Java类的结构语法相对来说非常稳定,其使用的就是访问者模式)。系统应该很少出现需要加入新节点的情况。其倾斜的可扩展性体现在:方法集合的可扩展性和类集合的不可扩展性。

设计模式-访问者(Visitor)模式的更多相关文章

  1. 设计模式之visitor模式,人人能懂的有趣实例

    设计模式,现在在网上随便搜都一大堆,为什么我还要写"设计模式"的章节呢? 两个原因: 1.本人觉得这是一个有趣的设计模式使用实例,所以记下来: 2.看着设计模式很牛逼,却不知道怎么 ...

  2. 设计模式之——visitor模式

    visitor模式,又叫访问者模式,把结构和数据分开,编写一个访问者,去访问数据结构中的元素,然后把对各元素的处理全部交给访问者类.这样,当需要增加新的处理时候,只需要编写新的 访问者类,让数据结构可 ...

  3. 设计模式C++描述----22.访问者(Visitor)模式

    一. 访问者模式 定义:表示一个作用于某对象结构中的各元素的操作.它你可以在不改变各元素的类的前提下定义作用于这些元素的新操作. 结构如下: 二. 举例 假设有一项科学实验,是用来对比两种种子在不同环 ...

  4. [设计模式]访问者 Visitor 模式

    访问者模式是对象的行为模式. 访问者模式的目的是封装一些施加于某种数据结构元素之上的操作.一旦这些操作需要修改的话,接受这个操作的数据结构则可以保持不变.

  5. 设计模式之Visitor模式(笔记)

    訪问者模式:表示一个作用于某个对象结构中的各元素操作.它使你能够不改变各元素的类的前提下定义作用于这些元素的新操作. 首先定义一个visitor抽象类,为每一个详细类声明一个visit操作 publi ...

  6. 设计模式:visitor模式

    核心:将数据结构和数据的处理分开 注意:注意函数的参数传递和调用关系 例子: class Element; class Visitor { public: virtual void Visit(Ele ...

  7. 设计模式 -- 访问者模式(Visitor)

    写在前面的话:读书破万卷,编码如有神--------------------------------------------------------------------主要内容包括: 初识访问者模 ...

  8. Visitor模式(访问者设计模式)

    Visitor ? 在Visitor模式中,数据结构与处理被分离开来.我们编写一个表示"访问者"的类来访问数据结构中的元素, 并把对各元素的处理交给访问者类.这样,当需要增加新的处 ...

  9. .NET设计模式访问者模式

    一.访问者模式的定义: 表示一个作用于某对象结构中的各元素的操作.它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作. 二.访问者模式的结构和角色: 1.Visitor 抽象访问者角色,为该 ...

随机推荐

  1. linux:系统启动流程

    系统启动流程 本文基于CentOS6 版本 黑色部分为主流程分支,蓝色部分为详细流程分支,绿色部分是注释部分 第一步--加载BIOS打开计算机电源,计算机会首先加载BIOS信息,主要负责检测系统外围关 ...

  2. GridView 控制默认分页页码间距 及字体大小

    GridView 控制默认分页页码间距 及字体大小 PagerCss TD A:hover { WIDTH: 20px; COLOR: black; padding-left: 4px; paddin ...

  3. Intellij IDEA创建包(package)问题解决方案

    问题 在使用IDEA创建包时会出现这样一种场景,就是当一个空包很长时,比如com.secbro.drools.model.这个时候如果你想给drools或model创建同级的包,你会发现,默认创建的包 ...

  4. D3.js 使用心得

    教程 D3.js 入门教程系列 http://www.ourd3js.com/wordpress/296/ 全球地图数据

  5. 单一功能学习——百度AI之身份证识别

    以下内容基本是从官方接口文档复制过来的,附带自己封装的代码 时间:2018年4月4日 一.导入工具包 使用maven依赖: <dependency> <groupId>com. ...

  6. caffe 卷积层的运算

    贾清扬寻找快速算法之路:https://github.com/Yangqing/caffe/wiki/Convolution-in-Caffe:-a-memo 卷积运算图文并茂:http://www. ...

  7. [svn]显示日志很慢 点击文件查看更改记录也贼慢

    特此记录,防止以后忘记. 解决办法: 在 C:\Windows\System32\drivers\etc (win7) 中加入 即可 亦或将代码的url中pc名字改为ip地址也可以解决问题 对文件夹点 ...

  8. TreeSet中自定义Comparator实现降序

    @Test public void test1() { TreeSet ts = new TreeSet<Integer>(new MyComparator()); ts.add(3); ...

  9. Linux常用命令 (转载自大牛笔记 --- http://www.weixuehao.com)

    Linux简介及Ubuntu安装 常见指令 系统管理命令 打包压缩相关命令 关机/重启机器 Linux管道 Linux软件包管理 vim使用 用户及用户组管理 文件权限管理 大牛笔记-www.weix ...

  10. Java--数组转成list,list转数组

    数组转成list: 方法一: String[] userid = {"aa","bb","cc"}; List<String> ...