21、Ruby 模块 (Module)

模块(Module) 是一种把方法、类和常量组合在一起的方式。

模块(Module) 定义了一个命名空间,相当于一个沙盒,在里边的方法和常量不会与其它地方的方法常量冲突

模块(Module)带来了两大好处:

1、 模块提供了一个命名空间和避免名字冲突;
2、 模块实现了mixin装置;

模块类似与类,但有一下不同:

  • 模块不能实例化
  • 模块没有子类
  • 模块只能被另一个模块定义

Ruby 模块语法

Ruby 语言中的模块定义语法格式如下

module <ModuleName>   
   statement1
   statement2
   ...........
end

1、 模块中的常量命名与类常量命名类似,以大写字母开头;
2、 模块中的方法定义看起来和类也相似;
3、 可以使用模块名称和两个冒号来引用一个常量;

范例

hello.rb

# !/usr/bin/ruby -w
# -*- encoding:utf-8 -*-
# filename: hello.rb
# author: DDKK.COM 弟弟快看,程序员编程资料站(www.ddkk.com)
# Copyright © 2015-2065 www.ddkk.com. All rights reserved.
module Hello
   PI = 3.141592654
   def Hello.sin(x)
   # ..
   end

   def Hello.cos(x)
   # ..
   end
end

Ruby 语言允许定义多个函数名称相同但是功能不同的模块

quick.rb

# !/usr/bin/ruby -w
# -*- encoding:utf-8 -*-
# filename: quick.rb
# author: DDKK.COM 弟弟快看,程序员编程资料站(www.ddkk.com)
# Copyright © 2015-2065 www.ddkk.com. All rights reserved.

module Quick
   VERY_BAD = 0
   BAD = 1
   def Quick.sin(badness)
   # ...
   end
end

可以像定义类方法一样,在模块中定义一个方法时,可以指定在模块名称后跟着一个点号,点号后跟着方法名

Ruby require 语句

require 语句用于加载模块

如果一个第三方的程序想要使用任何已定义的模块,可以使用 Ruby require 语句来加载模块文件

require 语法格式

require filename

文件扩展名 .rb 不是必需的

范例

# !/usr/bin/ruby -w
# -*- encoding:utf-8 -*-
# filename: main.rb
# author: DDKK.COM 弟弟快看,程序员编程资料站(www.ddkk.com)
# Copyright © 2015-2065 www.ddkk.com. All rights reserved.

$LOAD_PATH << '.'    

require 'quick.rb'
require 'hello'

y = Quick.sin(Trig::PI/4)
wrongdoing = Hello.sin(Moral::VERY_BAD)

使用** $ LOAD_PATH << '.'** 让 Ruby 知道必须在当前目录中搜索被引用的文件。 如果不想使用$` LOAD_PATH,那么您可以使用 require_relative 来从一个相对目录引用文件

注意

文件包含相同的函数名称。所以,这会在引用调用程序时导致代码模糊,但是模块避免了这种代码模糊,可以使用模块的名称调用适当的函数。

Ruby include 语句

Ruby 语言允许在类中嵌入模块

Ruby 语言提供了 include 语句用来在类中嵌入模块

include 语法格式如下

include modulename

注意

如果模块是定义在一个单独的文件中,那么在嵌入模块之前就需要使用 require 语句引用该文件

范例

week.rb

# !/usr/bin/ruby -w
# -*- encoding:utf-8 -*-
# filename: week.rb
# author: DDKK.COM 弟弟快看,程序员编程资料站(www.ddkk.com)
# Copyright © 2015-2065 www.ddkk.com. All rights reserved.
module Week
   FIRST_DAY = "Sunday"
   def Week.weeks_in_month
      puts "You have four weeks in a month"
   end
   def Week.weeks_in_year
      puts "You have 52 weeks in a year"
   end
end

现在,可以在类中引用该模块

main.rb

# !/usr/bin/ruby -w
# -*- encoding:utf-8 -*-
# filename: main.rb
# author: DDKK.COM 弟弟快看,程序员编程资料站(www.ddkk.com)
# Copyright © 2015-2065 www.ddkk.com. All rights reserved.

$LOAD_PATH << '.'
require "week"

class Decade
include Week
   no_of_yrs=10
   def no_of_months
      puts Week::FIRST_DAY
      number=10*12
      puts number
   end
end

d1=Decade.new
puts Week::FIRST_DAY
Week.weeks_in_month
Week.weeks_in_year
d1.no_of_months

运行以上 Ruby 范例,输出结果如下

$ ruby main.rb
Sunday
You have four weeks in a month
You have 52 weeks in a year
Sunday
120

Ruby 中的 Mixins

在继续阅读本节之前,你需要初步了解具备面向对象的概念

当一个类可以从多个父类继承类的特性时,该类显示为多重继承

Ruby 不直接支持多重继承,但是 Ruby 的模块(Module)有另一个神奇的功能。它消除了多重继承的需要,提供了一种名为 mixin 的机制

Ruby 语言没有真正实现多重继承机制,而是采用 mixin 机制作为替代品

将模块 include 到类定义中,模块中的方法就 mix 进了类中

范例

a.rb

# !/usr/bin/ruby -w
# -*- encoding:utf-8 -*-
# filename: a.rb
# author: DDKK.COM 弟弟快看,程序员编程资料站(www.ddkk.com)
# Copyright © 2015-2065 www.ddkk.com. All rights reserved.

module A
   def a1
   end
   def a2
   end
end

b.rb

# !/usr/bin/ruby -w
# -*- encoding:utf-8 -*-
# filename: b.rb
# author: DDKK.COM 弟弟快看,程序员编程资料站(www.ddkk.com)
# Copyright © 2015-2065 www.ddkk.com. All rights reserved.

module B
   def b1
   end
   def b2
   end
end

hello.rb

# !/usr/bin/ruby -w
# -*- encoding:utf-8 -*-
# filename: hello.rb
# author: DDKK.COM 弟弟快看,程序员编程资料站(www.ddkk.com)
# Copyright © 2015-2065 www.ddkk.com. All rights reserved.

$LOAD_PATH << '.'

require "a"
require "b"

class Hello
include A
include B
   def s1
   end
end

main.rb

# !/usr/bin/ruby -w
# -*- encoding:utf-8 -*-
# filename: main.rb
# author: DDKK.COM 弟弟快看,程序员编程资料站(www.ddkk.com)
# Copyright © 2015-2065 www.ddkk.com. All rights reserved.

require "hello"

samp= Hello.new
samp.a1
samp.a2
samp.b1
samp.b2
samp.s1

  • 模块 A 由方法 a1 和 a2 组成
  • 模块 B 由方法 b1 和 b2 组成
  • 类 Hello 包含了模块 A 和 B
  • 类 Hello 可以访问所有四个方法,即 a1、a2、b1 和 b2

可以看到类 Hello 继承了两个模块,可以说类 Hello 使用了多重继承或 mixin