使用另一个类的另一个实例的方法扩展实例

时间:2015-05-06 23:59:48

标签: ruby inheritance instance

目前,我正在执行类似以下内容的Runnable课程' run的{​​{1}}方法访问方法:

ExecutionContext

这个想法是class ExecutionContext def message(text) puts "ExecutionContext.message: #{text}" end def answer? puts "ExecutionContext.answer called" true end end class Controller def do_run(context) @context = context run @context = nil end def method_missing(mth, *args) @context.send(mth, *args) end end class Runnable < Controller def run if answer? message "Runnable's block executing!" end end end runnable = Runnable.new context = ExecutionContext.new runnable.do_run(context) 课程由&#34;最终用户&#34;谁想要访问从其他地方提供的Runnable实例的功能(例如messageanswer?方法)。实际上,ExecutionContext类是所有&#34;最终用户&#34;我们关注并且它应该尽可能小而简单。

上面的代码按预期工作,Runnable调用的所有方法都由Runnable.run提供。

但是我想知道是否有更优雅的方法来实现同样的目的,我可以避免使用ExecutionContext并定义临时method_missing实例变量。

理想情况下,我想将代码修改为与此类似的代码(@context保持不变):

ExecutionContext

是否有class Controller def do_run(context, runnable) runnable.extend_from_instance(context) runnable.run end end class Runnable def run if answer? message "Runnable's block executing!" end end end runnable = Runnable.new context = ExecutionContext.new Controller.new.do_run(context, runnable) 这样的事情?

更新

感谢大家对此进行调查。

由于我到目前为止已经提到了两个答案,我意识到我应该提到以下限制:不幸的是extend_from_instanceRunnable都不能变成ExecutionContext s。它们需要module es,因为它们的实例对于不同的情况会有不同的行为(两者都有自己的实例变量等)。

我真的需要执行class方法,就像它是run 实例(代码中的ExecutionContext)的一部分一样。

2 个答案:

答案 0 :(得分:1)

是的,在这种情况下,您不想使用method_missing

我真的不明白你想要完成什么。也许define_block不是正确的名字......?

但是,模块似乎具有您想要的功能。

module Messaging
  def message(text)
    puts "Provider.message: #{text}"
  end 
end

class Parent
  include Messaging
  ...
编辑:我认为你想使用绑定。它允许您将当前范围(上下文)传递给另一个范围。

def print_local binding
  puts 'local is ' + binding.eval('local')
end

def foo
  local = 'value'
  print_local binding
end

foo 
=> local is value

在这种情况下,print_local想要打印foo的local变量。但它无法访问它,因为local仅存在于foo的范围(或上下文)中。

因此,您可以将foo的范围作为binding传递。

请参阅binding

答案 1 :(得分:0)

我认为B Seven说的是正确的。在类Moduleinclude模块中创建共享功能最有意义。但是,如果您真的想要像extend_from_instance这样的东西,您可以使用Ruby的Object#extend方法在类的实例中动态扩展模块(尽管我认为这样是一个坏主意)。使用您想要的代码:

module ExecutionContext
  def message(text)
    puts "ExecutionContext.message: #{text}"
  end 
  def answer?
    puts "ExecutionContext.answer called"
    true
  end
end

class Controller
  def do_run(context_module, runnable)
    runnable.extend(context_module)
    runnable.run
  end
end

class Runnable
  def run
    if answer?
      message "Runnable's block executing!"
    end
  end
end

runnable = Runnable.new
Controller.new.do_run(ExecutionContext, runnable)

但是,这是一个坏主意,从长远来看可能会回来咬你。