初步解决方法
我们定义一个新的类DrawService,把所有的draw逻辑都写在这里面,代码如下:
这是类图:

你觉得这下解决问题了,因此准备再稍微测试一下就下班回家:
点击运行,输出:
这是怎么回事又仔细看了看自己的代码:“我确实传的是个Factory对象啊,应该输出draw factory”才对。认真的你又去查了一些资料,这才发现了原因。
解释原因
★ Dynamic/Late Binding
我们来看一下这段代码
当程序运行NodeService::getName的时候,它必须判断出参数Node的类型,到底是Factory,是School,还是Building,因为这样才能调用对应实现类的getName方法。那程序能够在编译阶段就拿到这个信息吗然不能,因为Node的类型是可能会根据运行环境而变化的,甚至有可能是另外一个系统传过来的,我们不可能在编译阶段拿到这个信息。程序能做的,就是先启动,在运行到getName方法的时候,看一下Node到底是什么类型,然后再调用对应类型的getName()实现,拿到结果。 在运行时(而不是编译时)决定调用哪个方法,这就叫做Dynamic/Late Binding。
★ Static/Early Binding
我们再来看另外一段代码
当我们运行到 drawService.draw(node) 的时候,编译器知道node的类型吗行时是肯定知道的,那为什么我们传了一个Factory进去,却输出了 draw node 而不是 draw factory 呢们可以站在程序的角度来想这个问题。DrawService中只有4个draw方法,参数类型分别是Factory, Building, School和Node,如果调用方传了一个City进来怎么办竟调用方可以自己实现一个City类传进来。这种情况下程序该调用什么方法呢们没有draw(City)方法,为了防止这种情况发生,程序在编译阶段就直接选择使用DrawService::draw(Node)方法。无论调用方传了什么实现进来,我们都统一使用DrawService::draw(Node)方法以确保程序安全运行。 在编译时(而不是运行时)决定调用哪个方法,这就叫做Static/Early Binding。 这也就解释了我们为什么输出了 draw node 。
最终解决方法
原来这是因为编译器不知道变量类型导致的,既然这样的话,我们直接告诉编译器这是什么类型好了。这能做到吗当然能做到,我们提前检测变量类型。
这段代码是可行的,但是就是写起来非常繁琐,我们需要让调用方判断node类型并选择需要调用的方法,有没有更好的方案,那就是Visitor Pattern,Visitor Pattern使用了一种叫做Double Dispatch的方法,它可以把路由的工作从调用方转移到各自的实现类中,这样客户端就不需要写这些繁琐的判断逻辑了,我们首先看一下实现后的代码是什么样的。
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!