为什么在初始化时没有使用setter方法?

时间:2013-12-12 15:24:22

标签: ruby oop

最近我一直在阅读“Ruby中的实用面向对象设计”,我注意到最好的做法之一是使用访问器方法而不是直接抓取@instance_variable。例如:

class Foo
  attr_accessor :bar

  def initialize(my_argument)
    @bar = my_argument
  end

  # bad
  # def lorem_ipsum
  #     @bar * 999
  # end

  # good
  def lorem_ipsum
    bar * 999
  end

end

保持DRY是有意义的,如果我需要以某种方式处理@bar之前实际抓住它的值。但是,我注意到initialize方法直接设置了@bar实例变量的值:

class Foo
  attr_accessor :bar

  def initialize(my_argument)
    @bar = my_argument #<-- why isn't self.bar = my_argument used here?
  end

这有什么理由吗?是不是应该使用setter方法而不是直接使用=运算符来设置实例变量的值?

4 个答案:

答案 0 :(得分:7)

你是对的,做

会更有意义
class Foo
  attr_accessor :bar

  def initialize(my_argument)
    self.bar = my_argument
  end
end

关于你是否应该尊重对象本身中的封装的论据不同,但如果你相信,那么,是的,你应该这样做。

答案 1 :(得分:2)

初始化程序在初始化时设置值。访问器允许您在对象已经实例化后通过符号访问(读/写)。

这篇文章可能会帮助您理解: What is attr_accessor in Ruby?

答案 2 :(得分:2)

实际上,setter可以在initialize中使用,与其他方法相同,但是没有接收器就不能使用setter。

我认为您可以使用a_foo.bar=self.bar=,但如果没有接收方,则无法使用bar=,因为在后一种情况下,bar将被视为本地变量而不是setter方法:

class Song
  attr_accessor :name
  def initialize(name)
    self.name = name
  end
  def test_setter1(value)
    @name = value
  end
  def test_setter2(value)
    name = value #name is local variable
  end
end

s = Song.new("Mike")
p s
s.test_setter1("John")
p s
s.test_setter2("Rosy")
p s

这导致:

#<Song:0x23a50b8 @name="Mike">
#<Song:0x23a50b8 @name="John">
#<Song:0x23a50b8 @name="John">

答案 3 :(得分:1)

虽然您可以在初始化中使用setter,如@uncutstone's answer所示,但您无法像在代码中的评论中那样使用它。

问题是Ruby会解释:

bar = my_argument

作为bar局部变量的赋值,而不是bar=方法的调用。

在“Why do Ruby setters need "self." qualification within the class?”中对此进行了相当广泛的讨论。