对象与方法

先教大家一句咒语: Ruby中,一切皆对象。

对象(Object)

Ruby是一门解释执行的动态语言,同时,它也是一门完完全全的面向对象语言。

对象,很好理解,它表示客观世界中某个具体的个体事物,它是面向对象世界中的基本单元。它是某一个类的具体实例, 一个对象,应该包含其唯一的标识符,属性(attributes)以及方法(Methods)。

属性(attributes)即为一个对象的特点,用于描述这个对象的个性,而方法(Methods),则为这个对象能够提供的服务,及其行为。

举个例子:

人类,是一个类别。 人类中某个个体,为张三。 他是男性,中国人,黄色人种。他会做饭,是大厨,他唱歌也很好听。

那么用Ruby代码来描述的话,应该是这样的:


# 人类
Class People

  attr_accessor :name, :gender, :race, :nationality

  def initialize(name='', gender='', race='', nationality='')
    @name = name
    @gender = gender
    @race = race
    @nationality = nationality
  end

end

# 上帝造了张三
person = People.new
person.name = "张三"
person.gender = '男'
person.race = 'yellow'
person.nationality = 'China'

def person.chef
  puts "good"
end

def person.sing
  puts "good"
end

上面的代码, Class即为创建一个类,比如People, 是指人类。

attr_accessor , 声明了People类的属性,比如,人类是有名字(name)、有性别(gender)、有种族(race)、有国籍(nationality)。

我们可以使用new方法,来使用People类来造一个对象,也就是一个人, 我们用person表示。

person = People.new

我们使用「点」来指定person的name,并赋与其值。

person.name = '张三'

而实际上,attr_accessor,是动态生成了类似下面的方法:

class People
  # ...

  def name
    @name
  end

  def name=(name)
    @name=name
  end

  # 其他属性方法类似
end

def,是声明一个方法, 为对象创建一个行为。 比如上面的person.name = '张三', 就是允许给person起名字。

而像下面这样的代码:

def person.chef
  puts "good"
end

当执行person.chef的时候,会输出‘good’。

则是给「张三」这个个体创建一个头衔,厨师(chef),代表他会做饭。这个会做饭的技能, 只是他这一个个体特有的,你可以再创建一个人「李四」来尝试一下:

other_person = People.new
other_person.name = '李四'

你可以让「李四」来调用chef方法, 则会报错。

消息传递

我们上面的代码中: person.chef , 我们叫它方法调用。

而Ruby更愿意把它称作,消息传递。

person,是一个对象, 是一个消息接收者。

chef,是一个消息。

通过一个「点」, 我们把chef这个消息传递给person, 假如person可以响应这个消息,那么它就会响应结果,否则,则报错无法响应。

消息传递,是对象之间传递信息的唯一手段。

还记得我们的咒语吗? Ruby中一切皆对象。我们使用Ruby,就是使用对象, 想让对象为你工作,那么你就得给他传递消息。

包括要设置对象自己的属性,也是使用消息传递的方式,这也是上面代码中为什么要有「attr_accessor」方法。

另一句咒语: Ruby中一切都是消息传递(「方法调用」)

所以,Ruby里各种内建数据结构,比如字符串、数组、Hash等,也内置了一些方法,你也可以用同样的方式来调用。可以去ruby-doc.org来查找这些方法。

Chef中的抽象

回头看我们的自动化管理工具Chef中的一些概念,我们更容易理解这种对象与消息的思想。

比如,在OpsCode给出的apache Cookbook中,设置attributes的一段代码:

node.default["apache"]["dir"] = "/etc/apache2"
node.default["apache"]["listen_ports"] = [ "80","443" ]

node, 即为一个对象,Chef中把具体要配置管理的服务器,抽象为一个类Node,而上面代码中的node,即为那个具体的要使用Chef进行配置管理的服务器或者是其他Chef可配置管理的任何东西。

思考:

结合本节的内容,来思考下面这段代码的意思?

node.default['apache']['dir'] = '/etc/apache2'