你可以添加这些代码到你的类定义中:
class Thing
attr_reader :description
attr_writer :description
# maybe some more methods here…
end
使用一个符号并调用 attr_reader
方法将会为命名与该符号(:description
)相匹配的实例变量(@description
)创建一个 get 访问器。
调用 attr_writer
方法类似的将会为实例变量创建一个 set 访问器。实例变量被认为是一个对象的“属性”(attributes),这就是为什么 attr_reader
和 attr_writer
方法是这样命名的。
- 符号(Symbols)
- 在 Ruby 中,一个符号是以冒号开头的(例如,
:description
)。Symbol 类在 Ruby 类库中定义,用来表示解释器中的命名。当你将一个或多个符号作为参数传递给attr_reader
(这是一个 Module 类的方法)时,Ruby 会创建一个实例变量和一个 get 访问器方法。此访问器方法返回相应变量的值;实例变量和访问器方法都会使用该符号命名。所以,attr_reader(:description)
会创建一个名为@description
的实例变量,以及一个名为description()
的访问器方法。
accessors2.rb 程序包含一些属性读取器的示例。Thing 类为 @name
属性明确定义了 get 访问器方法,编写这样一个完整的方法的好处是,可以让你进行额外的处理,而不是简单的对属性的值进行读写。这里的 get 访问器使用 方法返回 @name
的字符串值及其初始值的大写形式。
return @name.capitalize
end
当为 @name
属性进行赋值时,我不需要进行特殊的处理,所以我可以这么写:
attr_writer :name
- Attributes or Properties?
- 不要对术语感到困惑,在 Ruby 中,”Attribute” 相当于许多编程语言中的 “Propertie”。
当你想允许对一个变量同时可以进行读和写操作时,attr_accessor
方法提供了替代 attr_reader
和 attr_writer
方法的简洁语法。我已经使用它来访问 Treasure 类中的 value 属性:
attr_accessor :value
这等同于:
attr_reader :value
前面我说过,使用一个符号并调用 attr_reader
实际上会创建一个名字与符号相同的变量。attr_accessor
方法也是一样的。
在 Thing 类的代码中,因为 方法显式创建了变量,所以这并不明显。然而,Treasure 类没有在它的 initialize
方法中引用 @value
变量。只存在 @value
访问器的定义:
attr_accessor :value
在我的源文件代码的底部,每个 Treasure 对象创建后都单独设置了 value 的值。
t1.value
要绝对地确定属性访问器真的已经创建了 @value
,你可以使用 inspect
方法查看对象的内部。我在这个程序的最后两行代码就是这么做的:
puts "This is treasure1: #{t1.inspect}"
puts "This is treasure2: #{t2.inspect}"
属性访问器可以同时初始化超过一个属性,你可以传递一个用逗号分隔的符号列表:
attr_reader :name, :description
attr_accessor(:value, :id, :owner)
和往常一样,在 Ruby 中参数列表的括号是可选的,但在我看来(为了清楚起见)括号是必选的。
现在让我们看看如何将属性读写用在我们的冒险游戏中。加载 2adventure.rb 程序。你会看到我在 Thing 类中创建了两个可读的属性:name
和 description
。我同时也让 description
是可写的。然而,我不打算改变任何一个 Thing 对象的 name,所以 name
是不可写的:
我创建了一个用来返回描述 Treasure 对象的字符串的 to_s
方法。回想一下,所有的 Ruby 类都有一个标准的 方法,Thing.to_s
方法覆盖(替换)了默认的方法。当您希望实现适合特定类类型的新行为时,你可以覆盖现有的方法。