记住冻结对象中的方法

时间:2017-07-15 05:29:26

标签: ruby

我正在使用抽象语法树,其中每个顶点都是ggplot(mpg, aes(displ, hwy)) + geom_point() + facet_wrap(c("cyl", "drv")) 类的子类。此基类在第三方库中定义,Node对象在构造时冻结。

现在我正在执行一些遍历树的昂贵操作,有时是递归的,并且想要记住那些结果。下面是这样一个子类的示例,并使用“经典”Ruby模式记忆操作结果:

Node

但是,由于class DefNode < Node def visibility_scope @visibility_scope ||= VisibilityScopeResolver.new(self).resolve end end 构造函数冻结了对象,因此尝试分配给实例变量会导致错误:

Node

有没有办法(特意)在冻结的对象中执行memoization?理想情况下,不要覆盖每个子类中的构造函数。

2 个答案:

答案 0 :(得分:1)

我不确定“惯用语”,但是当我去过那里时,我在课堂上使用了哈希:

class DefNode < Node
  def self.visibility_scopes
    @visibility_scopes ||= {}
  end

  def visibility_scope
    self.class.visibility_scopes[__id__] ||=
      VisibilityScopeResolver.new(self).resolve
  end
end

答案 1 :(得分:0)

我最终做的是声明一个private编写器,它允许有条件地设置值,即使在冻结的对象中:

class DefNode < Node
  def visibility_scope
    resolved_visibility_scope ||= VisibilityScopeResolver.new(self).resolve
  end

  private

  attr_writer :resolved_visibility_scope
end

我选择了这个解决方案,因为它允许状态包含在实例本身中,这更容易推理,并且不会产生任何无法预料的副作用。这样做的一个缺点是,乍一看,它看起来并不像熟悉的“玫瑰记忆”模式。

值得注意的是,编写者也可以命名为visibility_scope,因为它只定义#visibility_scope=,因此不会与手动定义的读者冲突。然而,我选择给它一个不同的名称,以尽量减少混淆的可能性。