use*_*934 1 ruby inheritance private subclass superclass
在阅读了 Ruby 的访问控制之后,我了解到私有方法只能从类内部以及该类的子类中隐式调用。不过,我有一个例子,其中一个类似乎default_chain在其子类上调用私有方法,并且它仍然有效。查看以下代码(改编自 Sandi Metz 的实用 Ruby 面向对象设计):
class Bicycle
attr_reader :chain
def initialize(args={})
@chain = args[:chain] || default_chain
end
def parts
{
chain: chain
}
end
end
class RoadBike < Bicycle
def parts
super.merge(
handlebar_tape_color: "red"
)
end
private
def default_chain
"21-speed"
end
end
class MountainBike < Bicycle
def parts
super.merge(
suspension: "Manitou Mezzer Pro"
)
end
private
def default_chain
"10-speed"
end
end
RoadBike.new.parts # {:chain=>"21-speed", :handlebar_tape_color=>"red"}
MountainBike.new.parts # {:chain=>"10-speed", :suspension=>"Manitou Mezzer Pro"}
Run Code Online (Sandbox Code Playgroud)
这是怎么回事?
您弄错了 - 在您的示例中,不存在父类调用子方法之类的事情。
Ruby 中的方法/常量名称查找总是“自下而上”进行:首先我们检查该方法是否在对象的类中定义,然后在对象的类的超类中定义,依此类推(这是一个巨大的简化,因为 Ruby 的对象模型更复杂,更多这个稍后再说)。因此,在您的示例中,事情大致按以下顺序发生:
当您调用RoadBike.new运行时时,检查是否有为initializeRoadBike 类定义的方法。没有,所以我们使用为其父类定义的实现 - Bycicle(但执行上下文保持不变 - 它仍然是RoadBike实例)
当执行Bycicle#initialize运行时遇到另一个方法调用时 - default_chain. 此时,我们以完全相同的方式开始方法名称解析 - 从 RoadBike 上下文开始。RoadBike有自己的实现吗default_chain?是的,确实如此,所以我们简单地称呼它。
希望下面的婴儿示例能够清楚地说明这一点:
class Parent
def initialize
puts "Parent Initializer is called"
a
b
end
def a
puts "Parent a is called"
end
def b
puts "Parent b is called"
end
end
class Child < Parent
def b
puts "Child b is called"
end
end
pry(main)> Child.new
Parent Initializer is called
Parent a is called
Child b is called
Run Code Online (Sandbox Code Playgroud)
实际上,方法/常量解析机制更为复杂(包括所谓的单例类)。这是一个更大的主题,不太适合 SO 答案,所以我强烈建议阅读 Paolo Perotta 的“ Metaprogramming Ruby 2 ”,其中从非常实用的角度对该模型进行了很好的详细解释。
| 归档时间: |
|
| 查看次数: |
465 次 |
| 最近记录: |