属性的读与写

事实上,有一个更简单的方式实现相同的功能。所有你要做的就是使用两个特殊的方法,attr_readerattr_writer,后跟一个符号(symbol):

  1. attr_reader :description
  2. attr_writer :description

你可以添加这些代码到你的类定义中:

  1. class Thing
  2. attr_reader :description
  3. attr_writer :description
  4. # maybe some more methods here…
  5. end

使用一个符号并调用 attr_reader 方法将会为命名与该符号(:description)相匹配的实例变量(@description)创建一个 get 访问器。

调用 attr_writer 方法类似的将会为实例变量创建一个 set 访问器。实例变量被认为是一个对象的“属性”(attributes),这就是为什么 attr_readerattr_writer 方法是这样命名的。

符号(Symbols)
在 Ruby 中,一个符号是以冒号开头的(例如,:description)。Symbol 类在 Ruby 类库中定义,用来表示解释器中的命名。当你将一个或多个符号作为参数传递给 attr_reader(这是一个 Module 类的方法)时,Ruby 会创建一个实例变量和一个 get 访问器方法。此访问器方法返回相应变量的值;实例变量和访问器方法都会使用该符号命名。所以,attr_reader(:description) 会创建一个名为 @description 的实例变量,以及一个名为 description() 的访问器方法。
accessors2.rb

accessors2.rb 程序包含一些属性读取器的示例。Thing 类为 @name 属性明确定义了 get 访问器方法,编写这样一个完整的方法的好处是,可以让你进行额外的处理,而不是简单的对属性的值进行读写。这里的 get 访问器使用 String.capitalize 方法返回 @name 的字符串值及其初始值的大写形式。

  1. def name
  2. return @name.capitalize
  3. end

当为 @name 属性进行赋值时,我不需要进行特殊的处理,所以我可以这么写:

  1. attr_writer :name

@description 属性不需要特殊处理,所以我使用 attr_readerattr_writer 去获取和设置 @description 变量的值:

  1. attr_reader :description
  2. attr_writer :description
Attributes or Properties?
不要对术语感到困惑,在 Ruby 中,”Attribute” 相当于许多编程语言中的 “Propertie”。

当你想允许对一个变量同时可以进行读和写操作时,attr_accessor 方法提供了替代 attr_readerattr_writer 方法的简洁语法。我已经使用它来访问 Treasure 类中的 value 属性:

  1. attr_accessor :value

这等同于:

  1. attr_reader :value
  2. attr_writer :value

前面我说过,使用一个符号并调用 attr_reader 实际上会创建一个名字与符号相同的变量。attr_accessor 方法也是一样的。

在 Thing 类的代码中,因为 initialize 方法显式创建了变量,所以这并不明显。然而,Treasure 类没有在它的 initialize 方法中引用 @value 变量。只存在 @value 访问器的定义:

  1. attr_accessor :value

在我的源文件代码的底部,每个 Treasure 对象创建后都单独设置了 value 的值。

  1. t1.value = 800

即使从没有正式的声明,@value 变量却是真实存在的,我们能够使用 get 访问器获取其数值。

  1. t1.value

要绝对地确定属性访问器真的已经创建了 @value,你可以使用 inspect 方法查看对象的内部。我在这个程序的最后两行代码就是这么做的:

  1. puts "This is treasure1: #{t1.inspect}"
  2. puts "This is treasure2: #{t2.inspect}"
accessors3.rb

属性访问器可以同时初始化超过一个属性,你可以传递一个用逗号分隔的符号列表:

  1. attr_reader :name, :description
  2. attr_writer(:name, :description)
  3. attr_accessor(:value, :id, :owner)

和往常一样,在 Ruby 中参数列表的括号是可选的,但在我看来(为了清楚起见)括号是必选的。

2adventure.rb

现在让我们看看如何将属性读写用在我们的冒险游戏中。加载 2adventure.rb 程序。你会看到我在 Thing 类中创建了两个可读的属性:namedescription。我同时也让 description 是可写的。然而,我不打算改变任何一个 Thing 对象的 name,所以 name 是不可写的:

  1. attr_reader(:name, :description)
  2. attr_writer(:description)

我创建了一个用来返回描述 Treasure 对象的字符串的 to_s 方法。回想一下,所有的 Ruby 类都有一个标准的 to_s 方法,Thing.to_s 方法覆盖(替换)了默认的方法。当您希望实现适合特定类类型的新行为时,你可以覆盖现有的方法。