命名冲突

模块方法(特定的前缀为模块名称的那些方法)可以让你的代码免受意外命名冲突的影响。但是,模块中的实例方法没有这样的保护措施。假设你有两个模块 - 一个叫做 Happy,另一个叫做 Sad。它们每个都包含一个名为 mood 的模块方法和一个名为 expression 的实例方法。

happy_sad.rb
  1. module Happy
  2. def Happy.mood # module method
  3. return "happy"
  4. end
  5. def expression # instance method
  6. return "smiling"
  7. end
  8. end
  9. module Sad
  10. def Sad.mood # module method
  11. return "sad"
  12. end
  13. def expression # instance method
  14. return "frowning"
  15. end
  16. end

现在,一个类 Person 包含了这两个模块:

  1. class Person
  2. include Happy
  3. include Sad
  4. attr_accessor :mood
  5. def initialize
  6. @mood = Happy.mood
  7. end
  8. end

Person 类的 initialize 方法需要使用被包含模块之一的 mood 方法设置其 @mood 变量的值。实际上他们都有一个 mood 方法,但这没有问题;作为一个模块方法,mood 必须以模块名称开头,因此 Happy.mood 不会与 Sad.mood 混淆。

但 Happy 和 Sad 模块也都包含一个名为 expression 的方法。这是一个实例方法,当两个模块都包含在 Person 类中时,可以不带任何限定地调用 expression 方法:

  1. p1 = Person.new
  2. puts(p1.expression)

对象 p1 使用哪个 expression 方法?事实证明它使用最后定义的方法。在目前的情况下,这恰好是 Sad 模块中定义的方法,原因很简单,在 Happy 之后包含了 Sad 模块。如果更改包含顺序以在 Sad 之后包含 Happy,则 p1 对象将使用 Happy 模块中定义的 expression 方法的版本。

在开始创建大型而且复杂的模块并将其混入到你的常规基类中之前,请记住这个潜在的问题 - 即包含相同名称的实例方法将“覆盖”彼此。在我的小程序中发现问题可能是显而易见的。但在一个巨大的应用程序中它可能不那么明显!