Ruby中的委托

时间:2015-02-23 20:51:10

标签: ruby oop delegation

我有一个类Klass,它的构造函数接受一个参数。我们应该能够调用此对象上未在Klass中定义的方法。

我们可以链接多个方法,但最后,我们必须使用Klass#result来获得如下结果:

Klass.new(5).pred.pred.result

,此处的输出应为3。我尝试在method_missing中使用Klass并在对象的类上使用send,但如果没有我必须使用的result方法,那就可以了。有人可以解释如何通过授权来完成这项工作吗?

1 个答案:

答案 0 :(得分:1)

你可以这样做:

class Klass
  def initialize(number)
    @number = number
  end

  def result
    @number
  end

  def method_missing(method_name, *arguments, &block)
    if @number.respond_to?(method_name)
      @number = @number.method(method_name).call(*arguments, &block)
      return self
    else
      super
    end
  end

  def respond_to_missing?(method_name, include_private = false)
    # be sure to implement this...
  end
end

puts Klass.new(5).pred.pred.result # => 3

但这有问题。在这个特定的例子中,由于#pred返回一个新对象(它不会修改它被调用的对象),我们必须将实例变量重新分配给结果。它适用于返回新Integers的pred和其他方法,但Integer上的某些方法不返回Integer(例如Integer#even)。在这种情况下,你会遇到这种行为:

puts Klass.new(4).even?.result # => true

根据您的具体情况,这可能是您所追求的。或者,在您的情况下,所有方法都是被委托的对象变异该对象,而不是返回该对象的新实例,在这种情况下不需要重新分配。

我认为你不能使用Ruby现有的Delegator和SimpleDelegator结构,因为你可以将最终的#result调用链接到最后的唯一方法是每个委托的调用都返回Klass的实例。使用这些现有构造将导致委托调用返回其正常返回值,然后链接将返回返回值返回的任何对象。例如,使用上面的代码,您会看到以下行为:

puts Klass.new(5).pred.pred.class # => "Klass"

使用SimpleDelegator,您会看到此行为

require 'delegate'

class Klass2 < SimpleDelegator
  # Klass2 methods...
end

puts Klass2.new(5).pred.pred.class # => "Fixnum"

希望有所帮助。