Ruby 中引入 Module(模块),是为了提供单继承和多继承机制。 模块用关键字 module 定义,与定义类的 class 类似。 模块中的方法等的定义和类一样。 但模块不能被实例化,也不能从普通类继承。 模块是独立的,且一个模块对像是 Module 类的一个实例。 在类中可以通过 include 继承模块中的方法,因为是继承而不是复制,所以,当类中有相同命名的方法时,优先执行类中的方法。 模块最常用的两个用途是:命名空间(Namespace)和混入(Mix-in)。 前者解决了命名冲突,后者解决了代码的复用。 下面,主要用实例,介绍一下使用模块时的,include 和 extend 方法的区别。
该方法主要用来将一个模块包含到(混入)一个类或者其它模块。 在类定义中引入模块,使模块中的方法成为类的实例方法。 include 后的模块,出现在类的父类查找链上,实例方法调用时,若在本类中找不到方法。 将会沿着继承树,向上从模块中检索。
module Human
def eat
puts "eat"
end
end
class Boy
include Human
end
Boy.ancestors
=> [Boy, Human, Object, Kernel, BasicObject]
Boy.singleton_class.ancestors
=> [Class, Module, Object, Kernel, BasicObject]
Boy.new.eat
=> eat
在类定义中引入模块,使模块中的方法成为类的类方法。 extend 后的模块,出现在了类的单例父类的链上,类方法调用时,将会依次从链上检索。
class Girl
extend Human
# Same as the following line
# Girl.singleton_class.send :include, Human
end
Girl.ancestors
=> [Girl, Object, Kernel, BasicObject]
Girl.singleton_class.ancestors
=> [Human, Class, Module, Object, Kernel, BasicObject]
Girl.eat
=> eat
module Human
def self.included(base)
base.extend(ClassMethods)
end
def eat
puts "eat"
end
module ClassMethods
def sleep
puts "We don't sleep."
end
end
end
class Programmer
include Human
end
Programmer.new.eat
=> eat
Programmer.sleep
=> We don't sleep.
Programmer.ancestors
=> [Programmer, Human, Object, Kernel, BasicObject]
Programmer.singleton_class.ancestors
=> [Human::ClassMethods, Class, Module, Object, Kernel, BasicObject]
参考链接
Include vs Extend in Ruby
Ruby学习笔记-Module
2015-07-25