class 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
公共实例方法
源码
# 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
返回当前方法调用正在委托到的对象。
源码
# File lib/delegate.rb, line 340 def __setobj__(obj) __raise__ ::ArgumentError, "cannot delegate to self" if self.equal?(obj) @delegate_sd_obj = obj end
将委托对象更改为 obj。
需要注意的是,这不会导致 SimpleDelegator 的方法发生更改。因此,您可能只想将委托更改为与原始委托类型相同的对象。
这是一个更改委托对象的示例。
names = SimpleDelegator.new(%w{James Edward Gray II}) puts names[1] # => Edward names.__setobj__(%w{Gavin Sinclair}) puts names[1] # => Sinclair