【问题标题】:Delegation in RubyRuby 中的委托
【发布时间】:2015-04-25 07:58:07
【问题描述】:

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

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

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

这里的输出应该是3。我尝试在Klass 中使用method_missing 并在对象的类上使用send,但是如果没有我必须使用的result 方法,这将起作用。有人能解释一下如何通过委托来完成吗?

【问题讨论】:

  • Klass.new(5).pred.pred.result 严重违反了Law of Demeter。你应该重新考虑你的设计。或许只需调用self.get_result_for_second_pred_of(number) 的一个方法并在Klass 内完成所有工作?
  • 这不是我的设计,很遗憾我不能。我必须解决这个问题。

标签: ruby oop delegation


【解决方案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 返回一个新对象(它不会修改调用它的对象),我们必须将实例变量重新分配给结果。它适用于 pred 和其他返回新 Integer 的方法,但 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"

希望对您有所帮助。

【讨论】:

    猜你喜欢
    • 2014-08-09
    • 1970-01-01
    • 2013-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-12
    • 2023-04-03
    相关资源
    最近更新 更多