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,这又会引发 Parentself.custom_class_method 版本,而不是 Child的。这是一个问题,因为我没有得到预期的 "hello world",而是收到一条错误消息 "You haven't implemented me yet!"

Childself.custom_class_method 是否在 Parentself.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