消息委托是如何在Ruby中与钩子一起工作的?



在Sandi Metz的OOP Ruby书的6.5.2节中,讨论了基类发送钩子消息以允许子类在减少耦合的同时贡献信息。

在基类中,local_spares方法是默认的空散列。

首先,为什么对合并中的local_spares的调用被委托给子类中的local_spares实现,而不是基类中的local_spares ?

class Bicycle
#...
def spares
{tire_size: tire_size,
chain: chain}.merge(local_spares)
end
def local_spares
{}
end
end
class RoadBike < Bicycle
#...
def local_spares
{ tape_color: tape_color }
end
end

是否因为一旦RoadBike继承了Bicycle, spares就成为了RoadBike的一个方法,并且它首先在自己的类中"看起来"?

其次,基类local_spares在这里返回空散列的目的是什么?这个方法可以引发NotImplementedError,而不是强制其实现在子类(模板方法模式)?

首先,为什么对合并中的local_spares的调用被委托给子类中的local_spares的实现,而不是基类中的local_spares ?

这就是Ruby方法查找的工作原理。当您向对象发送消息时,Ruby遍历它的类、超类(es)和(前置/包含的)模块,直到找到一个具有相同名称的对应方法并调用它。

查找从对象的单例类开始,并遵循ancestors列表:

road_bike = RoadBike.new
road_bike.singleton_class.ancestors
#=> [#<Class:#<RoadBike:0x00007fe0b59b9478>>, RoadBike, Bicycle, Object, Kernel, BasicObject]

当您调用road_bike.spare时,Ruby在上面的列表中查找spare实例方法。我们可以在Ruby中像这样重建查找:(非常粗略地)

road_bike.singleton_class.ancestors.find do |mod|
mod.instance_methods(false).include?(:spares)
end
#=> Bicycle

它在Bicycle中找到spares并调用它。在该方法中,消息local_spares被发送到当前接收者(仍然是road_bike),并再次开始查找:

road_bike.singleton_class.ancestors.find do |mod|
mod.instance_methods(false).include?(:local_spares)
end
#=> RoadBike

这一次,Ruby在RoadBike中找到了相应的方法。

请注意,具有相同名称的方法可以在祖先列表中存在多次,例如有RoadBike#local_sparesBicycle#local_spares。Ruby总是根据祖先列表调用第一个。但是,您可以通过super从子类中调用超类方法。

其次,基类local_spares在这里返回空散列的目的是什么?这个方法可以引发NotImplementedError,而不是强制其实现在子类(模板方法模式)?

引发NotImplementedError在书中的例子中用于default_tire_size:

def default_tire_size
raise NotImplementedError
end

通过引发这样的错误,可以强制所有子类提供一个实现。

我认为主要的区别是不是所有的自行车变体都有本地备件。它是一个加法被合并到一个现有的散列中。通过在基类中提供默认值,您可以允许子类省略方法实现。

是的,一旦继承了Roadbike, spares就变成了Roadbike的一个方法。至于重写方法"local_spares"在roadbike中,当从roadbike类引用时,它被调用。

是因为一旦RoadBike继承了Bicycle, spares '成为' RoadBike的一个方法,并且它首先在自己的类中'看起来' ?

为什么我们有空散列"local_spares"是因为在Bicycle类中引用了local_spares,所以要避免"method not found";当spares被Bicycle的实例调用时。

根据逻辑,假设spares方法在所有嵌套类中都是通用的,因此它被添加到Bicycle类中。

相关内容

  • 没有找到相关文章

最新更新