命名冲突
模块方法(特定的前缀为模块名称的那些方法)可以让你的代码免受意外命名冲突的影响。但是,模块中的实例方法没有这样的保护措施。假设你有两个模块 - 一个叫做 Happy,另一个叫做 Sad。它们每个都包含一个名为 mood
的模块方法和一个名为 expression
的实例方法。
happy_sad.rb
module Happy
def Happy.mood # module method
return "happy"
end
def expression # instance method
return "smiling"
end
end
module Sad
def Sad.mood # module method
return "sad"
end
def expression # instance method
return "frowning"
end
end
现在,一个类 Person 包含了这两个模块:
class Person
include Happy
include Sad
attr_accessor :mood
def initialize
@mood = Happy.mood
end
end
Person 类的 initialize
方法需要使用被包含模块之一的 mood
方法设置其 @mood
变量的值。实际上他们都有一个 mood
方法,但这没有问题;作为一个模块方法,mood
必须以模块名称开头,因此 Happy.mood
不会与 Sad.mood
混淆。
但 Happy 和 Sad 模块也都包含一个名为 expression
的方法。这是一个实例方法,当两个模块都包含在 Person 类中时,可以不带任何限定地调用 expression
方法:
p1 = Person.new
puts(p1.expression)
对象 p1
使用哪个 expression
方法?事实证明它使用最后定义的方法。在目前的情况下,这恰好是 Sad 模块中定义的方法,原因很简单,在 Happy 之后包含了 Sad 模块。如果更改包含顺序以在 Sad 之后包含 Happy,则 p1
对象将使用 Happy 模块中定义的 expression
方法的版本。
在开始创建大型而且复杂的模块并将其混入到你的常规基类中之前,请记住这个潜在的问题 - 即包含相同名称的实例方法将“覆盖”彼此。在我的小程序中发现问题可能是显而易见的。但在一个巨大的应用程序中它可能不那么明显!