Ruby中的虚拟属性

时间:2014-12-24 16:57:35

标签: ruby attributes virtual

我正在阅读一篇ruby教程并尝试使用了解虚拟属性的方式。这是教程中显示的示例。

class Spaceship
  def destination
    @autopilot.destination
  end

  def destination=(new_destination)
    @autopilot.destination = new_destination
  end
end

ship = Spaceship.new
ship.destination = "Earth"
puts ship.destination

根据教程,理想情况下此代码应返回地球,但我遇到以下错误。

class.rb:7:in `destination=': undefined method `destination=' for nil:NilClass (NoMethodError) from class.rb:12:in `<main>'

我很抱歉,但无法确定缺失的部分。

2 个答案:

答案 0 :(得分:5)

您需要为@autopilot变量分配一些内容。

这样的事情应该有效:

class Spaceship
  def initialize
    @autopilot = Struct.new(:destination).new(nil)
  end

  def destination
    @autopilot.destination
  end

  def destination=(new_destination)
    @autopilot.destination = new_destination
  end
end

但是如果你想添加一个虚拟属性,那么将值保存为一个简单的实例变量,如下所示:

class Spaceship
  def destination
    @destination
  end

  def destination=(new_destination)
    @destination = new_destination
  end
end

答案 1 :(得分:1)

正如humza指出的那样,所写的代码将不起作用。

我怀疑作者打算写下面的内容,并希望指出虽然destination看起来像一个属性(我们可能会将消息destination发送到一个对象并获取预期的响应),没有相应的实例变量@destination 。我们可能会认为destination是一个虚拟属性。

class Spaceship
  def destination 
    dosomething 
  end

  def destination=(new_destination)
    @autopilot = new_destination
  end

  def dosomething
    @autopilot
  end
end 

ship = Spaceship.new
ship.destination ="Earth"
puts ship.destination

对象的行为可能就像下一个示例中所示的Spaceship类一样,也就是两个类的接口是相同的(在这种情况下,我们 do 有一个实例变量{{ 1}})。

@destination

发送给Class Spaceship对象的消息不需要知道(也不知道)内部实现。

虚拟属性得到了很好的处理here,并给出了一个更好的示例,其中定义了方法class Spaceship def destination @destination end def destination=(new_destination) @destination = new_destination end end ship = Spaceship.new ship.destination ="Earth" puts ship.destination 而没有任何相应的实例变量durationInMinutes。给出的解释非常简洁,我将完整引用它:

  

这里我们使用属性方法来创建虚拟实例变量。对于外界来说,durationInMinutes似乎是一个像任何其他属性一样的属性。但是,在内部,没有相应的实例变量。

作者继续:

  

这不仅仅是一种好奇心。在他的具有里程碑意义的“面向对象软件构建”一书中,Bertrand Meyer将其称为统一访问原则。通过隐藏实例变量和计算值之间的差异,您可以屏蔽世界其他地方的类实现。您可以自由地改变未来的工作方式,而不会影响使用您的类的数百万行代码。这是一个很大的胜利。