Ruby 从超类方法屈服于子类方法

Ruby Yield to Subclass Method from Superclass Method

在Ruby中,是否可以在不影响子类中的代码的情况下从超类方法屈服于子类方法?我试图避免在子类中调用 super

class SuperClass
  def do_something
    puts "getting ready..."
    # how to then yield back to the subclass do_something method?
    puts "done."
  end
end

class SubClass < SuperClass
  def do_something
    # how to first execute the superclass do_something method?
    puts "doing something ..."
  end
end

所需的功能是专门调用 SubClass.do_something 并接收以下输出:

"getting ready..."

"doing something..."

"done."


编辑:

也许真正的问题是:如何干燥下面的代码,使用任何 ruby 从所有子 类 中删除对 self.get_readyself.finish_up 的调用使那些 类 干燥的元编程技术:

class SuperClass
  def self.get_ready
    puts "getting ready ..."
  end

  def self.finish_up
    puts "done."
  end
end

class SubClassA < SuperClass
  def self.do_something
    self.get_ready
    puts "doing something ..."
    self.finish_up
  end
end

class SubClassB < SuperClass
  def self.do_something
    self.get_ready
    puts "doing something else, a little differently..."
    self.finish_up
  end
end

class SubClassC < SuperClass
  def self.do_something
    self.get_ready
    puts "doing something crazy..."
    self.finish_up
  end
end

如果您真的不愿意使用 super,这几乎是不可能的。

有了super,就很简单了:

class SuperClass
  def do_something
    puts "getting ready..."
    yield
    puts "done."
  end
end

class SubClass < SuperClass
  def do_something
    super.do_something do
      puts "doing something..."
    end
  end
end

另一方面,在不使用 super 的情况下,如果您对多种方法持开放态度,这将变得更简单:

class SuperClass
  def do_something
    puts "getting ready..."
    self.actually_do_the_thing
    puts "done."
  end
  def actually_do_the_thing
    raise NotImplementedError
  end
end

class SubClass < SuperClass
  def actually_do_the_thing
    puts "doing something..."
  end
end

Practical Object-Oriented Design in Ruby 中,Sandi Metz 建议您克服调用 super 的方法是在 super-class 中定义一个 "hook" 方法,唯一的工作就是克服-由子方法编写。在你的情况下,你可以这样做:

class SuperClass
  def self.do_something
    puts "getting ready..."
    do_something_child
    puts "done."
  end

  def self.do_something_child; end
end

class SubClass < SuperClass
  def self.do_something_child
    puts "doing something ..."
  end
end

SubClass.do_something