如何让 Ruby 中的 alias_method 使用子类的自定义方法?

wou*_*out 5 ruby inheritance class

假设我有一个包含三个子类的基类。基类有一个大多数子类通用的方法,它有一个别名:

class Beer
  def bottle_content
    '250 ml'
  end
  alias_method :to_s, :bottle_content
end

class Heineken < Beer
end

class Stella < Beer
end

class Duvel < Beer
  def bottle_content
    '330 ml'
  end
end
Run Code Online (Sandbox Code Playgroud)

现在,如果to_s在 的发散子类实例上调用该方法Duvel250 ml则返回而不是330 ml

我明白为什么;别名是在超类级别创建的。而且我知道这可以通过alias_method在发散类中重新定义 来解决。但是还有其他方法可以做到这一点吗?

显然,使用方法 forto_s会起作用:

class Beer
  def bottle_content
    '250 ml'
  end
  def to_s; bottle_content; end
end
Run Code Online (Sandbox Code Playgroud)

但也许有更优雅的方法?

col*_*nux 2

这是因为在运行时alias_method进行处理self

\n\n

编辑\n正如@J\xc3\xb6rg 评论的那样,我的解决方案可能会导致一些麻烦,具体取决于您的应用程序(多线程环境\xe2\x80\xa6)。您建议的实现to_s可能是最好的,而且在我看来也不是特别不优雅。

\n\n

一种方法是在初始化时(在类上)声明别名。

\n\n
class Beer\n  def initialize\n    self.class.alias_method :to_s, :bottle_content\n  end\n\n  def bottle_content\n    '250 ml'\n  end\nend\n
Run Code Online (Sandbox Code Playgroud)\n\n

这样,别名就会在实例的类上创建,即。Duvel在你的例子中。

\n

  • 然而,这意味着您只能有一个子类,因为对于您创建的每个实例,您都会覆盖该方法。因此,如果您有不同的子类,您将使用不同的实现覆盖该方法,这意味着无论您最后实例化什么类,*所有*对象都会表现得像这样,无论它们是哪个子类的实例。现在,由于所有子类最终都会表现相同,因此您可能根本没有不同的子类,如果您只有一个子类,那么您可能根本没有子类。 (5认同)