2.11. 核心语言——对象,类,方法-6
类方法
像上面使用 def 关键字定义的方法对类的实例可见,也就是实例方法。所谓实例,就是在类上通过调用 new 方法创建的对象。但是类也可以有类方法。它不是在实例上调用的,而是在类本身调用的。类方法有时被用来定义工厂方法,在返回一个类的实例前做一些事情,或者他们完全不创建任何对象,而仅仅是提供一些功能行为。
class Robot
def self.create(name, is_loud)
new(is_loud ? name.upcase : name.downcase)
end
def initialize(name)
set_name(name)
end
private
def set_name(name)
@name = name
end
end
p Robot.create("Marvin", true) # Robot(@name = "MARVIN")
p Robot.create("Eve", false) # Robot(@name = "eve")
在 Robot.create 中对 new 方法的调用有一个隐含的 self.
,所以说它是对 Robot.new
的调用。在一个类中, self 指的是类本身。然而在普通的方法中, self 指的是收到方法调用的对象。
实例方法和类方法的表示符号
当在文档中引用方法时,约定实例方法就是用 #
号表示,就像 Robot#name 这种格式能够被 ri
识别。比如我们前面讲的在那个 IRB 环境里面,我们键入 ri
然后输入 Array#map
就可以出现这个 Array 的 实例方法 map.
类方法用 .
来表示。就像 Robot.create
。
子类
一个类可以定义为另一个类的子类,是通过 <
来表示的。子类继承了父类所有的方法,他还能够复写父类的方法,然后添加自己的新方法。所有通过父类方法设置的实例变量在子类中都是可见的。如果子类复写了一个继承的方法,它就可以使用 super 这个关键字来调用它父类对该方法的实现。
class Transformer < Robot
attr_reader :name
private
def set_name(name)
super(name.reverse)
end
end
bot = Transformer.new("Blaster")
puts bot.name # returns "retsalB"
如果 super 没有在使用的时候没有跟任何参数,那么对当前方法的参数就会隐式传递给它。所以说在上面的代码中 super
等价于 super(name)
。
*String类的 reverse 方法
ri "String#reverse"
压力的反向是甜点——克服压力就能享受甜蜜。太有哲理了
类的嵌套
最后类也可以被嵌套。嵌套作为提供命名空间的一种方式。嵌套一个类在另一个类中并不影响它的行为,只是改变了它的名字。比如:
class MyApp
class Robot
# ...
end
end
Robot 这个类它并不从 MyApp 这个类继承任何行为,或者是能够识别到它的实例变量或类似任何这样的事情。嵌套不像在 Java 里面那种内部类,它所有的意义就在于在 MyApp 这个类以外,代码要引用 Robot 这个类的话,就必须要通过 MyApp::Robot。如果有很多的程序组件使用相似的类名,或者是一个类仅仅是在内部被另一个类使用而对系统的其他部分隐藏, 这就提供了将类名排除在全局作用域外,以避免冲突的一种方法。