为什么我们需要attr_accessor?

时间:2016-01-05 21:15:25

标签: ruby attributes

我无法理解为什么我们需要在类中声明attr_reader和attr_writer或attr_accessor。我阅读了thisthis个帖子,但这些帖子主要解释了它们是如何工作的,而不是它们为什么存在。

如果是

<html ng-app>
  <button ng-model="button" > abc  </button> 
  <button ng-disabled="button"> def </button> 
  <button ng-disabled="button"> ghi </button>
</html>

似乎有点多余,不得不告诉Ruby写入和读取年龄,而不能自动地在类外写入和读取实例变量。为什么我们需要在Class中设置reader和writer而不是以下代码并保存几行?

class Person
  attr_accessor :age
end

bob = Person.new
bob.age = 99
bob.age

3 个答案:

答案 0 :(得分:4)

OpenStruct的行为类似于OP的第二个片段:

require 'ostruct'

bob = OpenStruct.new
bob.age = 99
p bob.age # => 99

所以有一个选择。

答案 1 :(得分:3)

在许多面向对象语言中,您在对象的方法和对象的属性之间共享一个表。在Ruby中,所有对象的消费者都应该关注对象的方法。如果你在JS中有这个:

Tank:
   weight: 123
   moveForward: function()...
在Ruby中你会得到:

Tank:
  ivars:
     @weight = 123
  methods:
     weight: return @weight # or other implementation, or a proxy...
     move_forward...

拥有两个不同表的原因是允许对象决定如何存储数据以及是否存储数据,而不是从外部调用它的属性。这允许一个非常重要的优势:保持UAP。也就是说,无论是属性还是方法,你都可以从外部使用对象的方法(发送消息)。

这是一个很棒的功能,许多其他面向对象的语言要么忽略优化(避免间接)或疏忽/无知(python是一个主要的例子)。我在这里写了一篇关于这个主题的文章:http://live.julik.nl/2012/08/messages-versus-slots

回答问题的最后部分:

  

为什么我们需要在Class中设置reader和writer而不是以下代码并保存几行?

为了防止您在JavaScript中始终 的情况,您只能在对象的某个方法或属性中找到undefined,这将会将您的应用程序从您访问该属性的位置吹出许多行(或执行秒)。

在Ruby中,如果你这样做,你会得到一个例外,它会让你自己省下几千次,相信我。事实上,你可以创建一个接受任何getter / setter消息的对象,并且这样的对象已经存在 - 它是一个OpenStruct。由于速度问题,它的使用通常不是一种好的做法。

[1] pry(main)> require 'ostruct'
=> true
[2] pry(main)> s = OpenStruct.new
=> #<OpenStruct>
[3] pry(main)> s.foo = 1
=> 1
[4] pry(main)> s.bar = 2
=> 2
[5] pry(main)> s.foo
=> 1
[6] pry(main)> s.bar
=> 2
[7] pry(main)> s.x
=> nil

使用属性方法生成器的另一个好处是大多数Ruby文档引擎(RDoc和YARD)都会寻找那些更快地记录对象方法的引擎。

答案 2 :(得分:1)

因为它使代码更容易维护。

通过阅读类代码可以清楚地看到你期望发生的事情,以及你希望其他类可以访问这些变量。

如果没有这个外部代码可以简单地访问你的内部变量,然后如果你重构你的代码并删除或重命名这样的变量,外部代码会中断。

因此,访问器方法清楚地表明您打算让其他类访问这些方法

仅供参考:Ruby非常强大,如果您愿意,可以按照自己的方式继续工作。我不推荐这个,但我指出它,所以你会明白它是一个明确的选择是为了保持你的代码可读。但是如果你想看看如何做到这一点,请尝试运行代码......

<script type="text/ruby">

def puts(s)  # ignore this method, just dumps to the display
  Element['#output'].html = Element['#output'].html + s.to_s + "<br/>"
end

class OpenKimono
  def method_missing(name, *args)
    if name =~ /=$/
      instance_variable_set("@#{name[0..-2]}".to_sym, args[0])
    else
      instance_variable_get("@#{name}")
    end
  end
end

class MyClass < OpenKimono
end

foo = MyClass.new

foo.bar = 12

puts "foo.bar just set to 12, it now = #{foo.bar}"

foo.baz = 13

puts "foo.baz just set to 13, it now = #{foo.baz}"

puts "foo.manchu has never been set... what does it equal? #{foo.manchu}"

</script>


<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://rawgit.com/reactive-ruby/inline-reactive-ruby/master/inline-reactive-ruby.js"></script>
<div id="output" style="font-family: courier"></div>