You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ruby中如何从被包装对象调用委托类的方法?

这个问题的核心原因很明确——当MyObject#foo被委托执行时,它内部的self指向的是原始的MyObject实例,而不是你的MyDelegator代理对象。所以foo里调用的bar自然是原对象自己的版本,而不是你装饰后的"decorated bar"。

给你两种实用的解决办法:

方法一:针对性重写单个方法

如果你只需要修正少数几个方法(比如这里的foo),可以在MyDelegator里重写该方法,把原对象的方法绑定到代理实例上执行:

class MyDelegator < SimpleDelegator
  def bar
    "decorated bar"
  end

  def foo
    # 将原对象的foo方法绑定到当前代理实例,让执行上下文变成代理对象
    __getobj__.method(:foo).bind(self).call
  end
end

这样调用MyDelegator.new(MyObject.new).foo就会返回"foo decorated bar"了。原理是bind(self)把原方法的执行上下文替换成了代理实例,当foo内部调用bar时,会优先查找代理类中定义的装饰版本。

方法二:全局代理所有方法(适合多个方法需要装饰的场景)

如果你有很多方法需要处理,不想一个个重写,可以用method_missing自动拦截并绑定所有方法:

class MyDelegator < SimpleDelegator
  def bar
    "decorated bar"
  end

  def method_missing(name, *args, &block)
    if __getobj__.respond_to?(name, true)
      # 绑定原对象的方法到代理实例执行
      __getobj__.method(name).bind(self).call(*args, &block)
    else
      super
    end
  end

  # 必须实现respond_to_missing?以保证respond_to?的正确性
  def respond_to_missing?(name, include_private = false)
    __getobj__.respond_to?(name, include_private) || super
  end
end

这个方案会让所有原对象的方法都在代理实例的上下文执行,任何内部方法调用都会优先使用代理中的装饰版本。不过要注意:这种方式会改变所有方法的执行上下文,如果原对象的方法依赖自身的私有状态,可能会出现预期外的行为,建议测试后再使用。

内容的提问来源于stack exchange,提问作者Felix D.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 10:10:28