动态地将模块中的方法添加到类的特定实例

Posted

技术标签:

【中文标题】动态地将模块中的方法添加到类的特定实例【英文标题】:Add methods from modules to specific instances of a class dynamically 【发布时间】:2011-07-14 17:22:04 【问题描述】:

这是交易:我需要使用一些方法来扩展 Box 类的特定实例。我需要包含在模块中的方法,并且我希望 Box 实例能够动态地包含模块。 现在我正在使用带有 eval 的钩子:

class Box
  def after_initialize
    if self.injected_module.present?
      eval("class << self; include #self.injected_module; end")
    end
  end
end

它工作得很好,但是当我使用 eval 时我真的觉得很脏。我正在寻找类似的东西:

module_to_inject = self.injected_module
self.eigenclass.class_eval do
   include module_to_inject
end

但我无法让 eigenclass 运行 class_eval 而无需像以下猴子修补类:

class Box; def eigenclass; class << self; self; end end end

我是否有一种漂亮(且可靠)的方式来做到这一点?

【问题讨论】:

【参考方案1】:

我无法理解你的推理。 self.class.class_eval 在您的示例中可以正常工作,如下所示:

class Box
  def after_initialize
    self.class.class_eval do
      include(self.injected_module)
    end
  end
end

编辑:澄清 cmets。

使用Object#extend 将模块中的方法作为类方法包含(就像在 eigenclass 中定义它们一样),如下所示:

module MyModule
    def method
        puts "called from #self.inspect"
    end
end

class Box
    def self.injected_module
        MyModule
    end

    def require_module
        self.class.class_eval do
            extend self.injected_module
        end
    end
end

b = Box.new
b.require_module
Box.method
# prints "called from Box"

【讨论】:

这个解决方案的问题是它在类本身中添加了一个方法,而不是在eigenclass中。这样,如果我在执行此代码后创建另一个 Box 实例,该实例将获得新方法。我希望将这些方法作为单例方法包含到我正在创建的实例中! 我也无法理解这种推理。您似乎对“特征类”的概念感到困惑。 “eigenclass”是类的同义词,直接在类上调用的方法,如Box.method。然而,在这里,您将一个模块包含到一个类中,定义实例方法。你能试着澄清一下你到底想要什么吗? 我最好的猜测是,您正在返回一个单例实例,并希望将 Module 中的方法添加为类方法,因此您可以调用 Box.method 而不是调用实例上的方法,例如 @987654331 @。然后你应该使用Object#extend 而不是包含。 据我所知,eigenclass 不是 link 类的同义词 - 让我直截了当地说:我有一个 Box 的实例,我们称之为 boxie .我想将方法​​添加到 boxie(例如,可以通过其 eigenclass 拥有自己的方法),而不是 Box(class)。我要添加的方法位于模块 M 中,但如果不使用eval,我无法将它们包含到实例中,因为我无法将“实例方法”动态地直接包含到特征类中。 eigenclass 在 ruby​​ 术语中是 singleton classclass &lt;&lt; self 习惯用法使 self 成为定义方法的上下文,因此您定义的是类方法而不是实例方法。阅读this question 了解更多详情。你链接的是ruby的方法查找树。您只需要自己回答:您希望 Module 中的方法是实例方法(对于 boxie)还是类方法(对于 Box) - 第一个使用 include,后者使用 extend【参考方案2】:

您需要动态地将模块中的方法添加到 Box 的特定实例是 Kernel#extend 方法:

box.extend MyModule

另外,因为动词“to injection”在Enumerable#inject 的Ruby 中已经有了意义,描述这一点的最佳动词是“to extend”。

【讨论】:

以上是关于动态地将模块中的方法添加到类的特定实例的主要内容,如果未能解决你的问题,请参考以下文章

Python中的实例模块

每日一学之认识Spring中的AOP

如何正确地将参数传递给 Django 中的基于类的视图实例?

java静态资源(静态方法,静态属性)是程序一运行就加载到jvm中,还是当被调用的时候才进行加载呢?

20165303第三周学习总结

使用C语言为python编写动态模块--在C中实现python中的类