实例创建方法,例如
ClassName new
为了帮助提供一些细节,
我们可以在抽象类中写一个=算术方法,
然后将它们分派到子类中。
我们可以在实例创建中使用它吗?
我尝试过新的,但它失败了。导致一些预定义的基本新方法。
Double Dispatch
在这种情况下真的没有意义new
。双重分派背后的想法是,您无法通过仅分派给接收者来确定正确的行为。(单个)参数的类型对选择(分派)的行为具有相同的影响。换句话说,只有当你的方法有参数时,双重分派才有意义,new
因为它是一元的,它没有。
也就是说,您当然可以实现自己的new
方法来覆盖库存默认继承的方法。你可以让它做各种有趣的事情。通常会进行某种环境检查以确定哪个子类是合适的。
AbstractClass>>>new
^self platform = #unix
ifTrue: [SubclassThatLeveragesUnix basicNew]
ifFalse: [CrappyPCSubclass basicNew]
请注意,我们basicNew
在这里使用,而不是new
. 如果您使用过new
,则需要在这些子类中实现不同的覆盖,否则它只会继承并AbstractClass>>>new
再次重新发送消息。
...或者您可以执行以下操作:
AbstractClass class>>#new
^ (self platform concreteClassFor: self) basicNew initialize.
这基本上是相同的想法,但没有 ifs :)
双重调度的关键在于,通过交换主消息的接收者和参数,您再次调用虚拟调用,然后您将获得基于消息接收者及其参数选择方法的效果。因此,您需要有带有参数的消息。
这是双重调度的典型示例:将整数和浮点数相加并执行适当的转换。
Integer>>+ arg
^ arg sumFromInteger: self
Float>>+ arg
^ arg sumFromFloat: self
Integer>>sumFromInteger: anInt
<primitive adding to ints>
Integer>>sumFromFloat: aFloat
^ self asFloat + aFloat
Float>>sumFromFloat: aFloat
<primitive adding two floats>
Float>>sumFromInteger: anInt
^ self + anInt asFloat
现在 1 + 1.0 将首先在 Integer 上命中 +,然后是 sumFromInt:然后是 +,然后是 sumFromFloat。请注意,我们有足够的信息,因此我们可以缩短第二次 + 调用,
该示例显示的是,在第一次调用期间,动态消息解析在方法上找到(因此它定义为动态案例),然后通过交换参数和接收者,动态消息解析基于 arg 执行另一种案例。所以最后你会得到一个使用原始调用的两个对象选择的方法。现在关于您的问题:在 Pharo 类中,消息是动态查找的,因此您可以使用双重分派毫无问题地实现实例创建方法,但目标尚不清楚。
MyClass class>>newWith: arg
arg newFromMyClass: aClass