Delegator通过BasicObject透明度

时间:2012-07-09 20:42:38

标签: ruby delegates decorator

上下文:我试图在Ruby中设置一个Decorator模式。由于Decorator应该将所有未知方法委托给底层对象,因此我使用了Delegator类。 我本可以使用SimpleDelegator,但我想完全理解我在做什么。

所以我提出的基本代码是:

class Decorator < Delegator
  def initialize(component)
    super
    @component = component
  end

  def __setobj__(o); @component = o   end
  def __getobj__;    @component       end
  def send(s, *a);   __send__(s, *a)  end
end

这与SimpleDelegator的实现完全相同。看起来不错。

但我不想要的是处理Decorator的代码知道它正在操纵一个Decorator。我想要完全透明。

目前Decorator.new(Object.new).class已返回Decorator

所以我做了一点修改并想出了这个:

class Decorator < Delegator
  undef_method :==
  undef_method :class
  undef_method :instance_of?

  # Stores the decorated object
  def initialize(component)
    super
    @component = component
  end

  def __setobj__(o); @component = o   end
  def __getobj__;    @component       end
  def send(s, *a);   __send__(s, *a)  end
end

这样,我可以在装饰对象上安全地使用classinstance_of?,它会通过method_missing(由Delegator实现)将方法发送到底层对象。

问题是:我不明白为什么我必须取消:class:instance_of?。我可以看到BasicObject定义了:==,所以我不得不取消它,但那两个呢? 我查看了BasicObject文档和C代码中的一些内容,但没有找到任何内容。我在Delegator文档和代码中看起来一样,也没有找到任何东西。 似乎Delegator包含内核模块,但内核#class还是内核#instance_of?不存在。

这两种方法来自哪里?如果它们根本没有实现,为什么我需要取消它们? 我想我必须遗漏一些关于Ruby的对象模型的东西。

感谢。

1 个答案:

答案 0 :(得分:2)

您可以通过检查方法获得提示:

Decorator.instance_method(:class)
  # =>  #<UnboundMethod: Decorator(#<Module:0x00000102137498>)#class> 

该方法的所有者为Decorator,但实际上已在#<Module:0x00000102137498>中定义。所以有一个匿名模块来定义它。有意思......让我们来看看:

Decorator.ancestors
  # => [Decorator, Delegator, #<Module:0x00000102137498>, BasicObject] 

DelegatorBasicObject之间再次出现该模块。因此Delegator并非直接来自BasicObject。如果你查看lib/delegate.rb中的源代码,你会发现:

class Delegator < BasicObject
  kernel = ::Kernel.dup
  kernel.class_eval do
    [:to_s,:inspect,:=~,:!~,:===,:<=>,:eql?,:hash].each do |m|
      undef_method m
    end
  end
  include kernel
  # ...

因此制作了Kernel模块的副本,该副本没有to_sinspect等......但仍然有class和{{1 }}。它包含在instance_of?中,而这就是它们的来源。

请注意,Delegator通过包含Object模块继承了相同的方法(当然,它包括完整的模块):

Kernel

这在Object doc

中说明
  

对象在内核模块中混合,构成内置内核   功能全局可访问。虽然是Object的实例方法   由内核模块定义,我们选择在此处记录它们   为清楚起见。