Ruby继承与覆盖class方法
Ruby Inheritance and overwriting class method
我设置了两个class如下图
class Parent
def self.inherited(child)
child.custom_class_method
end
def self.custom_class_method
raise "You haven't implemented me yet!"
end
end
class Child < Parent
def self.custom_class_method
"hello world"
end
end
似乎在评估继承 Child < Parent
时,它会调用 self.inherited
,这又会引发 Parent
的 self.custom_class_method
版本,而不是 Child
的。这是一个问题,因为我没有得到预期的 "hello world"
,而是收到一条错误消息 "You haven't implemented me yet!"
Child
的 self.custom_class_method
是否在 Parent
的 self.inherited
完成评估后才进行评估?如果是这样,也许有解决办法吗?我是否应该不对父 class 进行 raise
检查?
我认为这应该澄清:
class Parent
def self.inherited(child)
puts "Inherited"
end
end
class Child < Parent
puts "Starting to define methods"
def self.stuff; end
end
输出清楚地表明 .inherited
在您打开新的 class 时被调用,而不是在您关闭它时被调用。因此,正如您所猜测的那样,Child.custom_class_method
在您尝试调用它时并不存在 - .inherited
看到的只是一张白纸。
(至于如何绕过它...不幸的是,如果没有更深入地了解您正在尝试做的事情,我不能说。)
模板pattern/lazy初始化可能会帮助解决您的问题。该代码假定子 classes 之间的不同之处在于数据库连接信息,可能只是一个 table 名称或可能是完全不同的数据库。父 class 拥有创建和维护连接的所有代码,让子只负责提供不同之处。
class Parent
def connection
@connection ||= make_connection
end
def make_connection
puts "code for making connection to database #{database_connection_info}"
return :the_connection
end
def database_connection_info
raise "subclass responsibility"
end
end
class Child1 < Parent
def database_connection_info
{host: '1'}
end
end
class Child2 < Parent
def database_connection_info
{host: '2'}
end
end
child1 = Child1.new
child1.connection # => makes the connection with host: 1
child1.connection # => uses existing connection
Child2.new.connection # => makes connection with host: 2
您必须将 self.inherited
包裹在 Thread.new
中
示例:
class Foo
def self.inherited klass
begin
puts klass::BAZ
rescue => error
# Can't find and autoload module/class "BAZ".
puts error.message
end
Thread.new do
# 123
puts klass::BAZ
end
end
end
class Bar < Foo
BAZ = 123
end
我设置了两个class如下图
class Parent
def self.inherited(child)
child.custom_class_method
end
def self.custom_class_method
raise "You haven't implemented me yet!"
end
end
class Child < Parent
def self.custom_class_method
"hello world"
end
end
似乎在评估继承 Child < Parent
时,它会调用 self.inherited
,这又会引发 Parent
的 self.custom_class_method
版本,而不是 Child
的。这是一个问题,因为我没有得到预期的 "hello world"
,而是收到一条错误消息 "You haven't implemented me yet!"
Child
的 self.custom_class_method
是否在 Parent
的 self.inherited
完成评估后才进行评估?如果是这样,也许有解决办法吗?我是否应该不对父 class 进行 raise
检查?
我认为这应该澄清:
class Parent
def self.inherited(child)
puts "Inherited"
end
end
class Child < Parent
puts "Starting to define methods"
def self.stuff; end
end
输出清楚地表明 .inherited
在您打开新的 class 时被调用,而不是在您关闭它时被调用。因此,正如您所猜测的那样,Child.custom_class_method
在您尝试调用它时并不存在 - .inherited
看到的只是一张白纸。
(至于如何绕过它...不幸的是,如果没有更深入地了解您正在尝试做的事情,我不能说。)
模板pattern/lazy初始化可能会帮助解决您的问题。该代码假定子 classes 之间的不同之处在于数据库连接信息,可能只是一个 table 名称或可能是完全不同的数据库。父 class 拥有创建和维护连接的所有代码,让子只负责提供不同之处。
class Parent
def connection
@connection ||= make_connection
end
def make_connection
puts "code for making connection to database #{database_connection_info}"
return :the_connection
end
def database_connection_info
raise "subclass responsibility"
end
end
class Child1 < Parent
def database_connection_info
{host: '1'}
end
end
class Child2 < Parent
def database_connection_info
{host: '2'}
end
end
child1 = Child1.new
child1.connection # => makes the connection with host: 1
child1.connection # => uses existing connection
Child2.new.connection # => makes connection with host: 2
您必须将 self.inherited
包裹在 Thread.new
示例:
class Foo
def self.inherited klass
begin
puts klass::BAZ
rescue => error
# Can't find and autoload module/class "BAZ".
puts error.message
end
Thread.new do
# 123
puts klass::BAZ
end
end
end
class Bar < Foo
BAZ = 123
end