在 OOPS 中,我们有一个称为封装的概念,这意味着对象的内部表示通常隐藏在对象定义之外的视图之外。只有对象“本身”才能弄乱它自己的内部状态。外面的世界不能。
每个对象通常由其状态和行为定义,在 ruby 中,实例变量称为对象的内部状态或状态,根据 OOPS,任何其他对象都不应访问该状态,因此我们遵守封装。
前任:class Foo
def initialize(bar)
@bar = bar
end
end
上面,我们定义了一个类 Foo 并且在初始化方法中我们初始化了一个实例变量(属性)或(属性)。当我们使用 new 方法创建一个新的 ruby 对象时,它又在内部调用 initialize 方法,当方法运行时,@bar 实例变量被声明并初始化,并将保存为对象的状态。
每个实例变量都有自己的内部状态,并且对对象本身来说是唯一的,我们在类中定义的每个方法都会根据方法定义和用途改变对象的内部状态。这里的initialize方法做同样的事情,比如创建一个新的实例变量。
var object = Foo.new(1)
#<Foo:0x00000001910cc0 @bar=1>
在后台,ruby 创建了一个实例变量 (@bar =1) 并将值作为对象的状态存储在对象“对象”中。我们可以使用“instance_variables”方法检查它,并且该方法根据对象的当前状态返回一个包含对象所有实例变量的数组。
object.instance_variables
#[
[0]: @bar
]
我们可以在上面看到“@bar”实例变量。它是在我们调用对象的初始化方法时创建的。默认情况下,这个“@bar”变量不应该是可见的(隐藏的),因此除了对象之外的其他人不能从内部看到它。但是,一个对象可能会弄乱它自己的内部状态,这意味着如果我们给它一种方法,它可以显示或更改值,这两个可以通过在类中创建一个新的实例方法来完成。
当我们想通过调用@bar 变量来查看它时,我们会得到一个错误,因为默认情况下我们看不到对象的状态。
show = object.bar
#NoMethodError: undefined method `bar' for #<Foo:0x00000001910cc0 @bar=1>
#from (irb):24
#from /home/.rvm/rubies/ruby-2.0.0-p648/bin/irb:12:in `<main>'
但是我们可以通过两种方法访问变量,这两种方法称为setter 和 getter方法,它们分别允许对象显示或更改其内部状态(实例变量/属性/属性)。
class Foo
def bar
@bar
end
def bar=(new_bar)
@bar = new_bar
end
end
我们已经定义了 getter(bar) 和 setter(bar=) 方法,我们可以任意命名它们,但里面的实例变量必须与我们想要显示或更改值的实例变量相同。setter 和 getter 在某种程度上违反了 OOPS 概念,但它们也是非常强大的方法。
当我们通过重新打开类并定义它们来定义这两个方法时,当我们用方法调用对象时,我们可以查看实例变量(此处为@foo)并更改其值。
object.bar
1
object.bar=2
2
object.bar
2
这里我们调用了 bar 方法(getter),它返回 @bar 的值,然后我们调用了 bar= 方法(setter),我们提供了一个 new_value 作为参数,它改变了实例变量(@bar)的值,我们可以通过调用 bar 方法再看一遍。
在 ruby 中,我们有一个名为attr_accessor的方法,它结合了 setter 和 getter 方法,我们将它定义在类内部的方法定义之上。attr_* 方法是创建方法的快捷方式(setter 和 getter)
class Foo
attr_accessor :bar
end
我们必须提供一个符号 (:bar) 作为 attr_accessor 方法的参数,该方法在内部创建 setter 和 getter 方法,方法名称作为提供的符号名称。
如果我们只需要一个 getter 方法,我们可以调用 attr_reader :bar 如果我们只需要一个 setter 方法,我们可以调用 attr_writer :bar
attr_accessor 创建 attr_writer 和 attr_reader 方法
我们可以为 attr_* 方法提供任意数量的实例变量,用逗号分隔
class Foo
attr_writer :bar
attr_reader :bar
attr_accessor :bar, :baz
end