Java 的双重分发与 Visitor 模式
双重分发(Double Dispatch)
什么是双重分发?
谈起面向对象的程序设计时,常说起的面向对象的「多态」,其中关于多态,经常有一个说法是「父类引用指向子类对象」。
这种父类的引用指向子类对象的写法类似下面这种:
另一种常用的形式是
那上面的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方法,会将自己的真实类型再次传递回visitor
此时,在visitor中,就能根据真实的类型来调用具体的方法,对应node 和 leaf 分别有类似这样的方法:
Visitor 总结起来一般是包含 visitor 接口,在visitor 接口中,包含各个即将被访问的 Element对象的处理逻辑。在 各个Element 的具体实现中,再将自己的类型传递回visitor 进行二次分发,实现确切逻辑的调用。
在Tomcat中的应用
Visitor 在Tomcat中也有应用,典型的是解析EL表达式。
比如org.apache.el.parser.Node
这个类中包含一个accept(NodeVisitor visitor)方法
实际的 Node 类型有很多,但在真实调用的这个时候,会通过
将真实类型传回visitor, vistor中会调用具体的方法,从而实现参数也能起到决定作用的功能。
这里一般会声明多个visit方法,然后上面的visit(this)会直接定位到目标方法上。
以上就是 Java 中的各类分发,以及 visitor这种模式通过模式的形式来实现双重分发的效果。
欢迎工作一到五年的Java工程师朋友们加入Java架构开发:744677563
本群提供免费的学习指导 架构资料 以及免费的解答
不懂得问题都可以在本群提出来 之后还会有职业生涯规划以及面试指导
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Spring_总结_02_依赖注入
一、前言 本文承接上一节:Spring_总结_01_Spring概述 在上一节中,我们了解了Spring的最根本使命、四大原则、六大模块以及Spring的生态。 这一节我们开始了解Spring的第二大原则中的依赖注入,这属于六大模块中的核心容器部分。 二、基本概念 1.什么是依赖注入 (1)我们经常说的控制反转(Inversion of Control —IOC)和依赖注入(Dependency Injection—DI),在Spring 环境下是等同的概念。 (2)控制反转是通过依赖注入实现的。 (3)所谓依赖注入指的是容器负责创建对象和维护对象间的依赖关系。而不是通过对象本身负责自己的创建和解决自己的依赖。 2.依赖注入的本质 创建应用对象之间协作关系(依赖)的行为通常称为装配。这也是依赖注入的本质。 3.依赖注入主要目的 依赖注入的主要目的是解耦。 因为通过装配,对象间的依赖关系不再由对象维护,而是交给容器维护,降低了耦合度。 耦合具有两面性: (1)紧密耦合的代码难以测试,难以复用,难以理解,并典型地表现出“打地鼠”式的bug特性。 (2)一定程度的耦合又是必须的——完全...
- 下一篇
Python学习-字符编码浅析
1.什么是字符编码 既然是简述那肯定是简单明了.字符编码,看名字就是一种字符的编码格式,由于计算机内部采用二进制,想要将人类的语言字符输入到计算机就需要一种编码格式,这就是字符编码.字符-------编码(字符编码表)----->二进制. 计算机存取人类输入的内容并不是直接保存的,因为计算机并不懂人的语言,每个国家还有每个国家的语言.那么怎么办呢?于是就有一种统一的规定,人类输入到内存中的信息都存为uncode字符编码格式的,再由内存存入计算机硬盘.硬盘有很多种编码格式,这是因为为了向下兼容.而我们在学习时只需要大致了解就行了. unicode:目前的计算机内存使用的就是这种编码格式,能够兼容万国的字符,与别的字符编码都有一种对应关系. utf-8:英文名为(8-bit Unicode Transformation Format)是一种针对Unicode的可变长度字符编码. gbk:是为了兼容汉字的字符编码 2.python2与python3的区别 python2:在python2中将文件读入到内存中使,解释器默认使用的是ASCII码.但是在文件的首行写上 coding:utf-...
相关文章
文章评论
共有0条评论来说两句吧...