1

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

class Foo
  attr_accessor :bar

  # lots of code omitted

  def baz
    'qux' if bar
  end
end

baz 方法的确切形式并不太重要 - 只是bar这里是对实例变量的 getter 方法的引用@bar,从实例的类中调用。我倾向于从@bar显式检索值。对此有意见吗?我从未在ruby​​ 样式指南或类似内容中看到任何内容。我个人发现,做前者会使阅读和理解变得更加困难,尤其是当类超过数百行时。

编辑:

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

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。

4

3 回答 3

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=第 24 页看到以下声明1376760915&sr=1-1 ,一本备受推崇的关于 Ruby 的书:“通过将变量包装在方法中来隐藏变量,即使是在定义它们的类中。” (强调补充)。它继续给出类中使用访问器方法进行访问的方法示例。

于 2013-08-09T16:43:23.647 回答
2

我倾向于从@bar 显式检索值。对此有意见吗?

是的,直接访问不像设计那样灵活。Getter 和 setter 可用于转换值。这就是为什么 Java 程序员花费半辈子的时间来为他们的私有变量敲出什么也不做的 setter 和 getter——他们想将 setter 和 getter 呈现为他们的 api,这允许他们在未来更改他们的代码以在途中转换值在不更改 api 的情况下进入或退出。

然后 ruby​​ 出现了简洁的 attr_accessor 方法,这意味着编写什么都不做的 setter 和 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 实例变量返回给客户端代码之前对其执行任何操作,例如将其转换为人类年龄,或从数据库中检索年龄。

于 2013-08-09T23:08:52.017 回答
1

使用 getter实际上更快,主要是因为attr_readerattr_accessor是用 C 而不是 Ruby 编写的。

作为一个已经编写 Ruby 代码几年的人,我认为 usingattr_*更具可读性。但这可能只是我已经习惯的事情。

于 2013-08-09T20:50:52.630 回答