2015-02-23 29 views
-1

我有一个类Klass,它的构造函数接受一个参数。我们应该能够调用这个对象的方法,这些方法在Klass中没有定义。Ruby中的委托代码

我们可以链多种方法,但最终,我们必须使用Klass#result来得到这样的结果:

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

,这里的输出应该是3。我试图在Klass中使用method_missing,并在对象的类上使用send,但是如果没有我必须使用的result方法,这种方法就可以工作。有人可以解释如何用代表团完成这件事吗?

+0

'Klass.new(5).pred.pred.result'严重违反了[Demeter法](https://en.wikipedia.org/wiki/Law_of_Demeter)。你应该重新考虑你的设计。也许只有一个方法调用'self.get_result_for_second_pred_of(number)'并完成'Klass'中的所有工作? – spickermann 2015-02-23 21:00:14

+0

这不是我的设计,我不能遗憾。我必须与此合作。 – mariya 2015-02-23 21:04:20

回答

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#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" 

希望有所帮助。

+0

感谢您提供清晰详细的解释! – mariya 2015-02-24 12:13:10