Programming Ruby-chapter 9

来源:互联网 发布:mac用什么解压软件 编辑:程序博客网 时间:2024/05/16 14:45

Modules

Modules 用来把方法、类以及常量等组织在一起。Modules 会给用户带来两个好处:

1、Modules 提供了一个名字空间,防止了名字冲突。

2、Modules 实现了 minxin 功能。

名称空间

当你准备开始越来越大的 Ruby 应用时,就会发现产生了大量可重用的代码-把相关的代码组织成库通过是很具有实用价值的。这样,你会把这些代码进行分隔,存储到不同的文件中,这样可以在不同的 Ruby 程序中使用。

通常,我们用类来组织这些代码,因此你可能把不同的类(或及其相关类)粘贴到不同的文件中。

但是,你也会碰到一些情况,可能有一些代码,不适合用类来组织。

首先,第一步你可以把所的这些东西(重用代码)组织到一个文件中,然后简单在你需要的地方加载这些文件。这是 C 语言常用的方式。但是,这个方法存在一个问题。假如你与一些三角函数的功能,如 sin、cos 等等,你把这些功能放置在一个文件中,如 trig.rb ,以备将来使用。同时,另一个人 (Sally)正在进行另一项工作,她也写了一些她常用的功能,其中就包括 be_good 和 sin,并把它们保存到 moral.rb ,另外,Joe ,正想写一个另外一个程序,需要加载 trig.rb 和 moral.rb 到他的程序中,但是在两个文件中都调用了 sin方法.这将是我们所不期望看到的。

解决问题的办法就是 module 机制。modules 定义了一个名字空间,在这个沙箱中,你定义的方法、常量都能够正常发挥作用,而不用担心和其他方法和常量产生冲突。我们把 Trig 的功能集中到一个 module 中,代码如下:

module Trig

  PI = 3.141592654

  def Trig.sin(x)

  #

end

  def Trig.cos(x)

  #

  end

end

而另一些在 the good and bad moral 中的方法可以这样组织:

module Moral

  VERY_BAD = 0

  BAD = 1

  def Moral.sin(badness)

  #

  end

end

 

Modules 的常量命名和类常量相似,首字母大写。方法定义也是一样的。

如果第三方程序需要使用这些 modules ,可以使用 ruby 的 require 语句来简单加载这两个文件并通过限定名来引用:

require 'trig'

require 'moral'

y = Trig.sin(Trig::PI/4)

wrongdong = Moral.sin(Moral::VERY_BAD)

像使用类方法一样,通过在方法前面加上 module 名的前缀来调用 module 方法。通过 ::来引用 module 方法,就像使用类常量一样。

 

Mixins

Module 另外一个有趣的功能。通过提供叫做 mixin 的东西,来大大减少了对多继承的需要。

在前面章节的例子中,我们定义了 module 方法,通过 module 前缀不引用的方法。如果你直觉感觉这类同于类方法,你下一步会想,“如何包含 module 的实例方法呢?”这个问题问得好,module 不可能包含其实例,因为 module 并不是类。但是,你可以在类定义中 include 一个 module。此时,所有的 module 方法对于类来说如同类方法一样可用。module 声明的方法已经和类融成一体了。实际上,mixed-in  的 module 更加像是一个超类。

module Debug

  def who_am_i?

    "#{self.class.name}(/##{self.id}):#{self.to_s}"

  end

 end

 

class Phonograph

  include Debug

#..

end

class EightTrack

  include Debug

  #..

end

ph = Phonograph.new("West End Blues")

et = EightTrack.new("Surrenalistic Pillow")

ph.who_am_i?    ->"Photograpsh(#935520):West End Blues"

et.who_am_i?     ->"EightTrack (#935500):Surrealistic Pillow"

通过 include 相应的 Debug module,Photograph 和 EightTrack 类都获得了 who_am_i 的实例方法。

在继续之前,我们可以得出关于include表达式的大量观点。首先,它与文件无关,C 程序员使用 #include 预处理符在编译之前将另一个文件的内容插入到当前文件中。而 ruby 的include 语句仅仅包含一个指向命名 module 的引用。如果 module 在另一个文件中,你必须使用 require 包含它(或者使用 load 来动态加载),然后才能使用 include来包含。第二,ruby 的 include 语句不是仅仅把把 module 的实例方法复制到目标类中,而是生成一个从目标类指向 module 的引用。如果多个类 include 的同一个 module,它们都指向同一个地方,如果你更改了 module 中定义的实例方法,即使你的程序正在运行,所有 include 此 module 的类都会立即生效。

minins 机制给予了我们一种可控制的方式来向类中增加功能。然而,当minin 中的代码和类中的代码开始交互时,其真正强大的能力才得以体现。我们以 ruby 标准的 minin 之 Comparable 为例:

你可能使用 Comparable 的minxin 来增加比较操作(<  <=  == >= >)以及 between? 方法到你的类中。这些要正常发挥作用, Comparable 假定这些类定义了一个 <=>操作符。因此,如果你准备写一个类,你定义一个<=>方法,然后 include Comparable,你就可以得到6个比较功能。

我们使用我们前面的 Song 类为例,通过其 duration 属性来比较。我们要做有就是include Comparable,然后实现<=>操作符:

class Song

  include Comparable

  def initialize(name,artist,duration)

  @name=name

  @artist = artist

  @duration=duration

end

def <=>(other)

  self.duration<=>other.duration

end

我们通过下面的测试用例来检查结果:

song1 = Song.new("My War", "sinatra", 255)

song2 = Song.new("bicylops", "Fleck", 260)

song1<=>    ->-1

song1 < song2      true

 

迭代和枚举 module -Iterator    Enumerable

待续

原创粉丝点击