双重分发(Double Dispatch)

什么是双重分发?

谈起面向对象的程序设计时,常说起的面向对象的「多态」,其中关于多态,经常有一个说法是「父类引用指向子类对象」。

这种父类的引用指向子类对象的写法类似下面这种:

Animal animal = new Dog();
animal.bark();

另一种常用的形式是

public class Keeper { 

     public void say(Animal a) {
System.out.println("Animal say");
} public void say(Dog dog) {
System.out.println("dog say");
}
}
Animal animal = new Animal();
Animal dog = new Dog();
Keeper keeper = new Keeper();
keeper.say(animal);
keep.say(dog);

那上面的keeper调用两次say的时候,会输出什么内容呢?会调用到两个不同的方法吗?

实际上在这两次调用的时候,都会调用到say(Animal a)这个方法。由于这些内容在编译期就能确实下来,这就是 Java 的 静态分发。

从上面的图我们看到,对于两次调用生成的字节码,确实都指向了say(Animal a)这个方法,运行时直接执行方法,输出了对应的内容。

那对应的animal.bark() 为什么最终会调用到 dog 类的方法?这是在运行时确定具体的方法接收者的类型并执行。这就是所谓的动态分发,在运行时确定具体的方法,实现面向对象的多态。

分发(Dispatch)

分发就是指最终确定一个要执行的方法的过程。

对于 Java 等静态语言来说,都是通过 单一分发(Single Dispatch)来进行的方法执行。

比如这样一行代码

dog.eat(new Bone()) 

最终执行要选择的eat方法,只会根据dog的具体类型选择到对应的方法,而传入的参数并不能影响到对应方法的选择,这种就是 single Dispatch

为了让传入的真实参数,这里就是Bone来真正起到作用,就需要用到Double Dispatch或者叫做Multiple Dispatch

也就是说最终决定调用方法是哪一个的,不仅仅是方法的接收者,还受参数类型的决定。

Visitor 模式

在GoF 的设计模式中,Visitor 模式就使用到了Double Dispatch 达到了调用真实对象的目的。

对于Visitor 模式,最常用的例子是树的遍历。比如在处理到节点和树叶时的方式有区别,此归通过 visitor 的双重分发,实现对于不同的 Element ,执行不同的内容。

代码类似这样:

node.accept(new ConcreateVisitor());
leaf.accept(new ConcreateVisitor());

node 中的 accept方法,会将自己的真实类型再次传递回visitor

public void accept(Visitor v) {
v.visit(this);
}

此时,在visitor中,就能根据真实的类型来调用具体的方法,对应node 和 leaf 分别有类似这样的方法:

public void visit(Node n);
public void visit(Leaf l);

Visitor 总结起来一般是包含 visitor 接口,在visitor 接口中,包含各个即将被访问的 Element对象的处理逻辑。在 各个Element 的具体实现中,再将自己的类型传递回visitor 进行二次分发,实现确切逻辑的调用。

在Tomcat中的应用

Visitor 在Tomcat中也有应用,典型的是解析EL表达式。

比如org.apache.el.parser.Node

这个类中包含一个accept(NodeVisitor visitor)方法

实际的 Node 类型有很多,但在真实调用的这个时候,会通过

public void accept(NodeVisitor visitor) throws Exception {
visitor.visit(this);

将真实类型传回visitor, vistor中会调用具体的方法,从而实现参数也能起到决定作用的功能。

public void visit(Node node) throws ELException {
if (node instanceof AstFunction) { AstFunction funcNode = (AstFunction) node; Method m = null; } else if (xxx) {
}

这里一般会声明多个visit方法,然后上面的visit(this)会直接定位到目标方法上。

以上就是 Java 中的各类分发,以及 visitor这种模式通过模式的形式来实现双重分发的效果。

Java 的双重分发与 Visitor 模式的更多相关文章

  1. Java设计模式(21)访问模式(Visitor者模式)

    Visitor定义:作用于某个对象群中各个对象的操作.它可以使你在不改变这些对象本身的情况下,定义作用于这些对象的新操作. 在Java中,Visitor模式实际上是分离了collection结构中的元 ...

  2. 《图解设计模式》读书笔记6-1 VISITOR模式

    目录 1. Visitor模式简介 2. 示例 2.1 类图 2.2 代码 3. 模式的角色和类图 4. 思路拓展 4.1 双重分发 4.2 开闭原则 4.3 难以增加ConcreteElement角 ...

  3. Visitor模式,Decorator模式,Extension Object模式

    Modem结构 Visitor模式 对于被访问(Modem)层次结构中的每一个派生类,访问者(Visitor)层次中都有一个对应的方法. 从派生类到方法的90度旋转. 新增类似的Windows配置函数 ...

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

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

  5. java开发中的23中设计模式详解--大话设计模式

    设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...

  6. java开发中的23中设计模式

    设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...

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

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

  8. Visitor 模式心得

    最近读到Visitor模式,还是一知半解的.偶然翻到Uncle Bob对该模式的推导过程,有所心得,和大家分享一下. Uncle Bob 的链接是: http://butunclebob.com/Ar ...

  9. Java设计模式(22)命令模式(Command模式)

    Command模式是最让我疑惑的一个模式,我在阅读了很多代码后,才感觉隐约掌握其大概原理,我认为理解设计模式最主要是掌握起原理构造,这样才对自己实际编程有指导作用.Command模式实际上不是个很具体 ...

随机推荐

  1. 敏捷开发与Scrum

    敏捷开发以用户的需求进化为核心,采用迭代.循序渐进的方法进行软件开发.在敏捷开发中,软件项目在构建初期被切分成多个子项目,各个子项目的成果都经过测试,具备可视.可集成和可运行使用的特征.换言之,就是把 ...

  2. QQ通讯录VS360通讯录对新建信息界面中草稿的处理

    在新建信息界面中,对草稿信息的处理. 1. QQ通讯录的处理是: 如果信息编辑框不为空,点击HOME键或者点击BACK键,保存草稿,同时结束新建信息界面. 如果收件人为空,也保存草稿,只是将收件人取名 ...

  3. ios实例开发精品文章推荐(7.23)

    ---------------------------------------------------------------------------------------------------- ...

  4. Linux中的lo回环接口详细介绍

    1.linux的网络接口之扫盲 (1)网络接口的命名 这里并不存在一定的命名规范,但网络接口名字的定义一般都是要有意义的.例如: eth0: ethernet的简写,一般用于以太网接口. wifi0: ...

  5. Java用JSONObject-lib来解析json串

    直接贴代码:(所需jar包:json-lib.jar,可能会关联一些其它的jar包,请自行搜索.) import java.util.ArrayList; import java.util.HashM ...

  6. JAVA RSA私钥 加密(签名) 对应 C# RSA私钥 加密(签名)

    非对称密钥RSA算法加解密在C#和Java之间交互的问题,这两天看了很多其他人写的文章,碰到了几个问题,最终解决问题. 参考地址:http://xw-z1985.iteye.com/blog/1837 ...

  7. HSSFWorkbook 与 XSSFWorkbook

    刚开始使用new HSSFWorkbook(new FileInputStream(excelFile))来读取Workbook,对Excel2003以前(包括2003)的版本没有问题,但读取Exce ...

  8. numpy、scipy、matplotlib、OpenCV安装及问题解决

    1 numpy 概述 numpy是Numerical Python的缩写,释义为数值的Python numpy弥补了作为通用编程语言的Python在数值计算方面能力弱.速度慢的不足(numpy的底层是 ...

  9. FreeSWITCH增加iLBC编码

    1. 安装ilbc库从第三方库里下载指定版本 git clone https://freeswitch.org/stash/scm/sd/libilbc.git ./bootstrap.sh ./co ...

  10. ekho安装及测试(中文文字转语音)

    1. 官网下载源码包 地址:http://www.eguidedog.net/ekho.php 2. 安装 xz -d ekho-7.5.tar.xz tar -xvf ekho-7.5.tar ap ...