Oop 多重调度:概念上的必要性?

Oop 多重调度:概念上的必要性?,oop,design-patterns,polymorphism,dynamic-dispatch,multiple-dispatch,Oop,Design Patterns,Polymorphism,Dynamic Dispatch,Multiple Dispatch,我想知道,如果面向对象语言对性能的影响可以忽略不计,是否应该在面向对象语言中包含多分派的概念(即内置支持,好像虚拟方法的动态分派也扩展到了方法的参数) 问题 考虑以下场景:我有一个包含动物类型的类层次结构(不一定是平面的)。在代码中的不同位置,我希望对动物对象执行一些操作。我不关心,也不能控制,这个对象引用是如何获得的。我可能通过遍历动物列表来遇到它,或者它可能作为方法的参数之一提供给我。我要执行的操作应该根据给定动物的运行时类型进行专门化。这些行动的例子如下: 为动物构建一个视图模型,以便在

我想知道,如果面向对象语言对性能的影响可以忽略不计,是否应该在面向对象语言中包含多分派的概念(即内置支持,好像虚拟方法的动态分派也扩展到了方法的参数)

问题 考虑以下场景:我有一个包含动物类型的类层次结构(不一定是平面的)。在代码中的不同位置,我希望对动物对象执行一些操作。我不关心,也不能控制,这个对象引用是如何获得的。我可能通过遍历动物列表来遇到它,或者它可能作为方法的参数之一提供给我。我要执行的操作应该根据给定动物的运行时类型进行专门化。这些行动的例子如下:

  • 为动物构建一个视图模型,以便在GUI中显示它
  • 构造一个表示这种动物的数据对象(稍后存储到数据库中)
  • 给动物喂食一些食物,但根据动物的类型给动物不同种类的食物(什么对它更健康)
所有这些示例都是在动物对象的公共API上操作的,但它们所做的不是动物自己的事情,因此不能放入动物本身

解决 一个“解决方案”是执行类型检查。但这种方法容易出错,并且使用反射特性,这(在我看来)几乎总是一种糟糕设计的迹象。类型只能是编译时概念

另一个解决方案是“滥用”(某种)访问者模式来模拟双重调度。但这需要我改变我的动物来接受访客

我相信还有其他办法。此外,还应该解决扩展的问题:如果新类型的动物加入了团队,需要调整多少代码位置,以及如何可靠地找到它们

问题 因此,根据这些需求,多重分派不应该是任何设计良好的面向对象语言的一个组成部分吗?
让外部(而不仅仅是内部)动作依赖于给定对象的动态类型不是很自然吗?

致以最良好的祝愿

一个“解决方案”是执行类型检查。但这种做法是错误的 容易出错,并且使用反射特性,这(在我看来)是 几乎总是一个坏设计的迹象。类型应该是 仅编译时概念

你错了。虚拟函数、虚拟继承等的所有使用都涉及反射特性和动态类型。在需要时将键入延迟到运行时的能力是绝对关键的,甚至在您所处的情况的最基本公式中也是固有的,如果不使用动态类型,这种能力甚至不可能出现。你甚至把你的问题描述为想根据不同的情况做不同的事情。。动态类型。毕竟,如果没有动态输入,为什么需要做不同的事情呢?您已经知道具体的最终类型

当然,一点运行时键入可以解决您在运行时键入时遇到的问题


只需从类型到函数构建一个字典/哈希表。您可以为任何动态链接的派生类型动态地将条目添加到此结构中,这是一个很好的查找O(1),不需要内部支持。

您建议基于方法名/签名并结合运行时实际参数类型进行动态调度。我觉得你疯了

因此,根据这些需求,多重分派不应该是任何设计良好的面向对象语言的一个组成部分吗

对于某些问题,您所设想的调度策略的可用性将简化编码,这是将此类调度构建到任何给定语言中的一个薄弱论点,更不用说每个OO语言了

让外部(而不仅仅是内部)动作依赖于给定对象的动态类型不是很自然吗

也许,但并非所有看似“自然”的东西实际上都是好主意。比如说,衣服不是天然的,但如果你尝试在公共场合不穿衣服(不管怎么说,伯克利以外的地方),看看会发生什么

一些语言已经有了基于参数类型的静态分派,更传统地称为“重载”。另一方面,如果要考虑多个参数,则基于参数类型的动态调度将是一个真正的混乱,而且它会非常缓慢(er)。今天流行的OO语言允许您在需要的地方执行双重分派,而无需在绝大多数不需要的地方支持它


此外,尽管实施双重分派确实会带来因独立组件之间紧密耦合而产生的维护问题,但有一些编码策略可以帮助保持这种可管理性。无论如何,在给定的语言中内置基于参数的多个分派在多大程度上确实有助于解决这个问题还不清楚。

如果一个人将自己局限于这样一种情况,即必须在类X或类Y中存储关于X类型的对象应如何绑定或绑定Y类型的对象的知识,可以让Y的基本类型包括一个方法,该方法接受X的基本类型的引用,并指示一个对象知道如何被该引用标识的对象所吸收,以及一个要求Y拥有一个X的方法

这样做之后,可以使用
X
Fnorble(Y)
方法,首先询问
Y
它对被特定类型的
X
所吸收的信息了解多少。如果
Y
X
更了解
Y
,那么
X
Fnorble(Y)
方法应该调用Y