类 SimpleDelegator
作为 Delegator
的具体实现,此类提供了一种机制,可以将所有支持的方法调用委托给构造函数中传入的对象,甚至可以使用 __setobj__
在以后更改委托到的对象。
class User def born_on Date.new(1989, 9, 10) end end require 'delegate' class UserDecorator < SimpleDelegator def birth_year born_on.year end end decorated_user = UserDecorator.new(User.new) decorated_user.birth_year #=> 1989 decorated_user.__getobj__ #=> #<User: ...>
一个 SimpleDelegator
实例可以利用 SimpleDelegator
是 Delegator
的子类这一事实,通过调用 super
来调用委托到的对象上的方法。
class SuperArray < SimpleDelegator def [](*args) super + 1 end end SuperArray.new([1])[0] #=> 2
以下是一个简单的示例,它利用了 SimpleDelegator 的委托对象可以随时更改这一事实。
class Stats def initialize @source = SimpleDelegator.new([]) end def stats(records) @source.__setobj__(records) "Elements: #{@source.size}\n" + " Non-Nil: #{@source.compact.size}\n" + " Unique: #{@source.uniq.size}\n" end end s = Stats.new puts s.stats(%w{James Edward Gray II}) puts puts s.stats([1, 2, 3, nil, 4, 5, 1, 2])
打印
Elements: 4 Non-Nil: 4 Unique: 4 Elements: 8 Non-Nil: 7 Unique: 6
公共实例方法
__getobj__() { || ... } 点击切换源代码
返回当前正在委托方法调用的对象。
# File lib/delegate.rb, line 318 def __getobj__ unless defined?(@delegate_sd_obj) return yield if block_given? __raise__ ::ArgumentError, "not delegated" end @delegate_sd_obj end
__setobj__(obj) 点击切换源代码
将委托对象更改为 obj。
需要注意的是,这 **不会** 导致 SimpleDelegator 的方法发生改变。因此,您可能只想将委托更改为与原始委托类型相同的对象。
以下是如何更改委托对象的示例。
names = SimpleDelegator.new(%w{James Edward Gray II}) puts names[1] # => Edward names.__setobj__(%w{Gavin Sinclair}) puts names[1] # => Sinclair
# File lib/delegate.rb, line 340 def __setobj__(obj) __raise__ ::ArgumentError, "cannot delegate to self" if self.equal?(obj) @delegate_sd_obj = obj end