6.1 Java模拟 双分派(Double Dispatch)

通过Java模拟双分派(double dispatch),自然地获得访问者模式,从而认识访问者模式的本质
摘要由CSDN通过智能技术生成

[最后编辑2019.12.8]

Java模拟 双分派(Double Dispatch)、访问者模式 (visitor pattern)、表达式问题(The Expression Problem)

本章通过Java模拟双分派(double dispatch),自然地获得访问者模式,从而认识访问者模式的本质;通过解释器模式(5.3)进一步理解表达式问题。

6.1Java模拟 双分派

本文应用命令模式,在Java中模拟双分派(Double Dispatch)。最后的模拟结果,或者说,最后源代码的意义,揭示了访问者(Visitor)模式的本质。所以阅读本节,忘记一切理论和想法,仅仅关注源代码上的各种变化。

6.1.1 分派

分派/ dispatch是指运行环境按照对象的实际类型为其绑定对应方法体的过程。【注意:本文的分派,指运行时的绑定。不要讨论什么静态多分派、动态多分派】

主流的面向对象语言如C++、Java、C#等,在方法调用上仅支持单分派(single dispatch),即其分派仅仅基于消息接收者的动态类型(实际类型)。例如有抽象类型Shape定义了抽象方法m(),其两个具体子类圆/Circle和正方形/Square给出自己的实现。对于声明类型为Shape的变量obj,消息表达式obj.m()会按照obj的实际类型,绑定子类型的方法体。

Shape obj =(Shape)God.create("5-Shape"); //Circle或Square
       obj.m();//动态绑定

如果有test(Shape s)方法如下,对于其中的s.m()调用,也是动态绑定。

    public static void test (Shape s){
        s.m();
    }

假定有重载方法foo(Circle)和foo(Square),一个Shape对象能否按照其实际类型自动绑定合适的重载方法呢?

Shape obj = (Shape)God.create("Shape "); //Circle或Square
foo(obj); //编译异常,Shape类型参数不匹配

遗憾的是,Java对于重载方法是静态/编译期绑定的。如果Circle或Square对象声明为父类型,Java只按照obj的声明类型,静态地绑定了方法体。编译器将寻找foo(Shape),但目前只有foo(Circle)和foo(Square),因此报出编译异常。如果添加foo(Shape),不论obj的实际类型是什么,都会执行foo(Shape)的方法体。

双分派,对于消息表达式a.m(b),能够按照a和b的实际类型为其绑定对应方法体

上述内容就是Java等语言的程序员面临的现状。对于消息表达式a.doSth(b),能否按照a和b的实际类型为其绑定对应方法体呢?如果能够,就是双分派。换言之,双分派对于重载方法也能够动态绑定,即在调用foo(Shape)时,按照实际类型调用foo(Circle)或foo(Square)。因此,Java中模拟双分派的任务是,在调用foo(Shape)时,能够区分重载的方法

【或许有人会说:将foo(Circle)和foo(Square)的代码分别封装到各具体子类的m()中,然后通过foo(Shapes)调用s.m(),这样就可以达到“区分重载的方法”的效果。的确如此,可能这就是主流的面向对象语言不支持双分派的原因。同时,foo(Circle)和foo(Square)也不符合依赖抽象类型的原则。然而,本节不考虑必要性,本节的目标使用Java语言模拟双分派。】

Java模拟双分派时,已经能够动态绑定的部分可以先忽略,现在仅仅需要处理的,是在调用foo(Shape)时,能够正确执行重载的方法。所有的重载的方法foo(Circle)和foo(

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值