Ruby-Module初探

原创 2015年11月18日 21:01:32

Ruby-Module初探

module是什么?

Ruby里有一种叫module的东西,他和我们比较熟知的Class有很多类似之处,同样是组合一堆常量、变量和方法的单元,但是module不能像类一样被实例化。
Class被定义为Module的子类,但Class不只是module的一个子集,Class的某些独有的特性是module不具备的,比如继承或派生的概念。

扩展阅读:

那Class怎么成为Module子类的?

module的两大用途

1. 命名空间(Namespace)

我们可以使用module去构建某一模组的命名空间,这一模组可能包括一些方法或属性,甚至包括一些类,class其实也构建了命名空间,但是module比class显得更简洁、可控,我们可以打开module去为其添加新的属性、方法或类,但是这种更改是静态或是全局的。
比如,如果我们要写一套用于BASE64编解码的功能模块,因为BASE64是一套既定的规则(算法),我们没必要去定义一个类,然后每次要做BASE64编解码的时候,在内存空间中去一个新建一个对象来使用类中的方法;或者到这里我们想到了在类中定义静态方法来避免新建动态对象,的确,在诸如Java这样的语言中,我们习惯这样做,但是Ruby能为我们提供更纯粹的方式,那就是定义一个module:

module Base64
  def self.encode(plain_text)
    # do_encoding
  end

  def self.decode(base64_str)
    # do_decoding
  end
end

编解码是一个很泛的概念,比如还有URL编码、图片编码、视频编码等等,现在我们定义这个模块,就我们实现的编解码方法划定了一个特定命名空间;有了这个模块,我们就可以从以下方面来灵活应用:
一方面,在想做编解码的地方,可以用模块加半角圆点前缀的方式(如Base64.encode(pain_text))直接调用这个模块所提供的方法;
请注意到,我们在模块方法的定义中都加了self.前缀,如果我们想单独使用这个模块而不是作为其它模块或类定义的一部分,这是必要的,因为module的使用实际上和class相差无几,而module又不能实例化,我们需要将其定义为这个module对象(module也是对象哦!那self就是当前正在定义的这个module)的单例方法(静态方法);当然,如果这个模块里的所有方法都想要有被单独使用的能力,那我们可以通过extend的方式来简化代码的编写,就像下面这样:

module Base64
    extend self

    def encode(plain_text)
      # do_encoding
    end

    def decode(base64_str)
      # do_decoding
    end
end

另一方面,如果我们想为一个正在定义中的模块或类增加BASE64的处理能力,那我们就可以通过module的第二个强大的功能来完成这个需求,这个功能就是下面我们提到的混入。

2. 混入(Mixins)

前文提到module没有继承和派生的概念,我们不能用继承关键字去继承一个module,如果要在一个特定Class (ConcreteClass)中去使用另一个已定义的module (ConcreteModule),我们需要使用include的方式将ConcreteModule里定义的东西组装到我们当前所要设计的单元中来,然后ConcreteModule里定义的东西就好像我们直接在ConcreteClass里定义的一样。

# demo_include_module.rb
module ConcreteModule
  ConstA = 'constant A defined in ConcreteModule'

  def method_a
    puts 'method_a defined in module ConcreteModule'
  end
end

class ConcreteClass
  include ConcreteModule

  def method_b
    puts 'method_b defined in class ConcreteClass'
  end
end

puts ConcreteClass::ConstA
ConcreteClass.new.method_a
ConcreteClass.new.method_b

# demo_include_module.rb
module ConcreteModule
  ConstA = 'constant A defined in ConcreteModule'

  def method_a
    puts 'method_a defined in module ConcreteModule'
  end
end

class ConcreteClass
  include ConcreteModule

  def method_b
    puts 'method_b defined in class ConcreteClass'
  end
end

puts ConcreteClass::ConstA
ConcreteClass.method_a
ConcreteClass.new.method_a

执行这段Ruby代码:

> ruby demo_include_module.rb

将会得到如下输出:

constant A defined in ConcreteModule
method_a defined in module ConcreteModule
method_b defined in class ConcreteClass

如果我们想让ConcreteModule中的方法变成ConcreteClass的类方法,只需将类名后面的include换为extend来引入ConcreteModule即可。

# demo_extend_module.rb
module ConcreteModule
  ConstA = 'constant A defined in ConcreteModule'

  def method_a
    puts 'method_a defined in module ConcreteModule'
  end
end

class ConcreteClass
  extend ConcreteModule

  def method_b
    puts 'method_b defined in class ConcreteClass'
  end
end

puts ConcreteModule::ConstA
ConcreteClass.method_a
ConcreteClass.new.method_a

然后执行代码:

> ruby demo_extend_module.rb
constant A defined in ConcreteModule
/xx/yy/demo_extend_module.rb:20:in `<top (required)>': undefined method `method_a' for #<ConcreteClass:0x2e663c8> (NoMethodError)
method_a defined in module ConcreteModule
    from -e:1:in `load'
    from -e:1:in `<main>'

Process finished with exit code 1

可以看到,extend引入的模块里的方法变成了目标类(对象)的单例方法,而且Ruby不允许我们像调用实例方法那样去在一个new出来的对象上调用单例方法。

扩展问题:

  1. 如果ConcreteModule本来就extend了self,那我们再通过include的方式引入ConcreteModule会有什么效果?
  2. ConcreteModule中定义的常量会以怎样的方式进入ConcreteClass?

上文提及的include和extend就是module的混入,通过混入,我们可以引入预先定义的各种模块,组成更强大的模块或类,并且能够方便地从模块中获得静态方法和实例方法。

钩子方法

我们在定义一个module时,还可以为其定义钩子方法,钩子方法名以动词的过去分词形式出现,当模块被以不同方式(include, extend)加入其它模块或类时,对应的*ed(过去分词)回调方法将得到调用,有了钩子方法,我们可以去监控定义了钩子方法的模块被其它定义所引用的情况:

# demo_module_included_hook.rb
module ConcreteModuleBase
  def self.included(other)
    puts "#{other} included #{self}"
  end
end

class ConcreteClass
  include ConcreteModuleBase
end

# cc = ConcreteClass.new

执行包含以上代码的.rb文件:

>ruby demo_module_included_hook.rb
ConcreteClass included ConcreteModuleBase

通过输出结果我们可以看到,程序侦测到了ConcreteModuleBase被引用的情况,这里已经体现了Ruby动态编程的些许魅力(关于Ruby动态编程,这里暂不讨论)!
除了included, extended, 我们还可以定义inherited, method_added, singleton_method_added等钩子方法来侦测不同行为的发生,真是很nice的一个特性。

小结

以上讨论了module的基本概念,两大用途,以及Ruby的钩子机制怎样去监控一个特定module是怎样被引用或是被扩展的,这些远不是module的全部内涵,比如模块函数(module_function)、作用域(scope),还有module的加载机制,均未涉及。
module的更多机制、特性或是用法技巧,有待更多的讨论和发掘。本次讨论,我们以最后一个扩展问题来结束:

扩展问题:

Ruby中没有专门定义接口(interface),为什么?

Ruby模块Module

模块(Module)是一种把方法、类和常量组合在一起的方式。模块(Module)为您提供了两大好处。 模块提供了一个命名空间和避免名字冲突。 模块实现了 mixin 装置。 模块(M...
  • wlchn
  • wlchn
  • 2015年10月16日 15:16
  • 185

Ruby-Module初探

Ruby里有一种叫module的东西,他和我们比较熟知的Class有很多类似之处,同样是组合一堆常量、变量和方法的单元。...
  • mashroomxl
  • mashroomxl
  • 2015年11月18日 21:01
  • 611

大数据初探

一、什么是大数据 5V特点(IBM提出):Volume(大量)、Velocity(高速)、Variety(多样)、Value(价值)、Veracity(真实性)。 应用:发现隐藏事物、商品相似性推荐、...
  • shuke1991
  • shuke1991
  • 2016年05月18日 19:00
  • 222

小白...

初入软件行业,代码小白一枚...还望各位大牛指点迷津,多谢多谢.
  • taoxiaowu36
  • taoxiaowu36
  • 2016年06月25日 22:25
  • 132

新人学ruby---ruby中的模块

模块模块是什么ruby同JAVA一样只支持单继承,每个类只能有一个父类,为了提高程序的灵活性ruby引入了 **模块** 为实现多重继承提供了可能。模块可以说是类的一个补充,但是模块于类有两个不同:模...
  • hsj880921
  • hsj880921
  • 2015年09月29日 00:03
  • 568

ruby模块的概念、定义和使用

1.模块的概念        模块(Module)是一种把方法、类和常量组合在一起的方式。模块(Module)为您提供了两大好处。 a)模块提供了一个命名空间和避免名字冲突。 b)模块实现了 ...
  • wangjianno2
  • wangjianno2
  • 2016年06月18日 03:39
  • 586

MongoDB初探系列之一:MongoDB安装及建议配置

想必第一次听说MongoDB的各位小伙伴,一定是听到他的诸多很N的地方才决定来学习一下这个东东的。不管你是出于什么目的开始踏上这段学习之旅,但是同样作为菜鸟的我很乐意和各位一起成长。废话不多说了,各种...
  • zhaoguoshuai91
  • zhaoguoshuai91
  • 2015年07月11日 21:26
  • 1020

SEO初探

SEO初探 人类搜索的方式:搜索步骤 体验对答案,解决方案或者信息片段的需求,导航型、交易型、信息型查询。 用一串单词和短语(查询)阐述需求。 执行查询,查看结果中是否有所...
  • liyuxing6639801
  • liyuxing6639801
  • 2018年01月21日 10:26
  • 36

【Ruby】模块扩展方法介绍

当我们要扩展类的方法时,我们可以采取Mixin的方式将模块中的方法添加到类中,下面会对实现的几种方式进行详细介绍。...
  • sunset108
  • sunset108
  • 2015年10月18日 13:48
  • 1130

学习笔记1:Ruby模块:module

我们使用模块的的主要目的是用来组织代码,模块化代码,有点类似命名空间,但却有很大的不同 一、创建和使用模块 用module关键字来定义模块 module没有实例,我们使用时把module混合到类中...
  • u013435984
  • u013435984
  • 2016年12月08日 18:50
  • 113
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Ruby-Module初探
举报原因:
原因补充:

(最多只允许输入30个字)