ruby样式和实例变量

时间:2013-08-09 16:32:22

标签: ruby instance-variables

我在很多代码中看到的东西:

class Foo
  attr_accessor :bar

  # lots of code omitted

  def baz
    'qux' if bar
  end
end

baz方法的确切形式并不太重要 - 这里只是bar是对实例变量@bar的getter方法的引用,从实例的类中调用。我倾向于明确地从@bar检索值。对此有何意见? 我从未在ruby style guide或类似内容中看到任何内容。我个人觉得做前者会让人更难阅读和理解,特别是当课程超过几百行时。

修改

也许为了说明我认为这个设计的尴尬,让我们重新评估一个非常标准的初始化方法:

class Foo
  attr_accessor :bar, :qux

  def initialize(bar, qux)
    @bar = bar
    @qux = qux
  end
end

如果我们使用setter方法,我们不能通过类比使用bar = ?。相反,我们有:

class Foo
  attr_accessor :bar, :qux

  def initialize(bar, qux)
    self.bar = bar
    self.qux = qux
  end
end

失去了第一个优雅的一些。我们有一个更灵活的设计,因为我们现在可以自由地重写我们的setter方法并取消attr_writer。但我只是在风格方面有一些观点,感觉很像配置而不是相反,而Russ Olsen已经宣称设计'模式'不仅仅是Rails而是Ruby也是如此。

3 个答案:

答案 0 :(得分:5)

通过getter访问属性具有提供封装的优势。在某些方面,使用实例变量来存储值是一个实现细节。当然,情况是否合适。但是,我不记得读过任何明确的这种风格问题了。

找到https://softwareengineering.stackexchange.com/questions/181567/should-the-methods-of-a-class-call-its-own-getters-and-setters,从与语言无关的角度讨论该问题。还发现https://www.ruby-forum.com/topic/141107,这是特定于ruby的,虽然它没有打破任何新的基础,更不用说暗示Ruby标准了。

更新:刚刚在http://www.amazon.com/Practical-Object-Oriented-Design-Ruby-Addison-Wesley/dp/0321721330/ref=sr_1_1?s=books&ie=UTF8&qid=1376760915&sr=1-1第24页发表了以下声明,这是一本备受推崇的关于Ruby的书:“隐藏变量,甚至来自定义它们的类,用方法包装它们。“ (重点补充)。它继续使用访问器方法提供类中方法的示例。

答案 1 :(得分:2)

  

我赞成明确地从@bar中检索值。有没有   对此的看法?

是的,直接访问不如设计灵活。 getter和setter可用于转换值。这就是为什么java程序员花费一半的时间来为他们的私有变量做出任何不做任何setter和getter的事情 - 他们希望将setter和getter作为他们的api,这允许他们在将来改变他们的代码来改变路上的值在不改变api的情况下进出。

然后ruby带来了整洁的attr_accessor方法,这意味着写作什么都不做,而且getter不再是痛苦的。

Python更进了一步。在python中,实例变量是公共的,你可以直接访问它们,例如

print my_dog.age 

编写python程序的java程序员将实现get_age()和set_age()方法:

class Dog:
    def get_age(self):
        return self.age

    def set_age(self, age):
        self.age = age
然后,java程序员将飞越该地区的所有城镇,并将描述getter和setter方法的传单作为获取和设置age实例变量的api,并且他们会警告人们不要直接访问实例变量 - - 或者其他事情可能会破裂。

然而,python有一个功能,允许程序员消除getter和setter,直到他们真正需要做一些有用的事情 - 而不是愚蠢地获取或设置一个值。 Python允许您将客户端代码对实例变量的直接访问转换为方法调用。对客户来说它是透明的。例如,客户端代码可能通过写:

来访问类中的实例变量
my_dog.age  
Python允许类的编写者随后实现一个名为age()的方法,并且my_dog.age可以调用该方法而不是直接访问实例变量(请注意,在python中,与ruby不同,你可以通常在没有括号的情况下调用方法。然后,新实现的age()方法可以在将其返回到客户端代码之前对age实例变量执行任何操作。将其转化为人类年,或从数据库中检索年龄。

答案 2 :(得分:1)

实际上是faster to use a getter,主要是因为attr_readerattr_accessor是用C而不是Ruby编写的。

作为已经编写Ruby几年的人,我认为使用attr_*更具可读性。但这可能只是我已经习惯的东西。