ruby 学习笔记 5 - class&module&methods

本文有 2442 字,大约需要 6 分钟可以读完, 创建于 2012-03-11

和其它的面向对象语言类似,ruby的类方法也分为_class method_ 和 instance method, moduleclass具有相当大程度的相似性, 但是用于重用module中定义的方法时( 同样也有 class method 和 instance method 之分 ),又有一些微妙的差异。

class method定义

遵循perl的设计哲学,ruby中的class method也有三种方法,分别如下:

  1. 类内define法,需要在 method name 之前显示加上 self 指明这是个属于 class 的方法:
class Test
    def self.foo
        puts "class method called"
    end
end
# call
Test.foo
  1. Append 法,通过 « 添加到 self,如下:
class Test
    class << self
        def foo
            puts "class method called"
        end
    end
end

# call
Test.foo
  1. 类外定义,和定义一个普通函数的方法类似,但是指明了 class name, 可以用于方便的向已定义好的类中添加 class method:
class Test; end
def Test.bar
    puts "class method called"
end
#call
Test.bar

include/extend

当 module 中的方法被新的类通过MIXIN方法包含的时候,module中定义的方法在新的类中是被定位为 class method 还是定义为 instance method? 答案取决于包含 module 的方法,这里是一段测试代码:

    module TestModule
    def foo
        puts "foo"
    end
end

class NewClsIncludeModule
    include TestModule
end

class NewClsExtendModule
    extend TestModule
end

begin
    NewClsIncludeModule.foo
    NewClsIncludeModule.new.foo
rescue Exception => e
    puts e
end

begin
    NewClsExtendModule.foo
    NewClsExtendModule.new.foo
rescue Exception => e
    puts e
end

运行结果如下:

undefined method `foo` for NewClsIncludeModule:Class
foo
undefined method `foo` for #<NewClsExtendModule:0x9c4436c>

这里的输出表明:

  • 以 include 方法包含的 module 其定义的方法会被解析为 instance method, 即 include 包含 instance methods
  • 以 extend 方法包含的 module 其定义的方法会被解析为 class method, 即 extend 扩展 class methods

扩展 module 的习惯用法

尽管 include 和 extend 分别用于扩展 instance method 和 class method, 我们还是可以采用一种惯用法来同时包含一个module的 instance methods 和 class methods. Rails 就利用了这种惯用法: 用 include 同时添加 instance methods 和 class methods。其原理如下:

  1. 任何 object 都是Object的子类实例,而 Object 本身继承自Kernel
  2. Kernel module 定义了 include 方法,其中会调用 self.included
  3. 这个 included 可以被用来修改包含 module 方法的类
  4. 定义 module 的时候,用一个 sub module 来定义所有的 class methods
  5. 在 module 中重写 included 方法,调用 extend 来扩展上述 sub module 中的 methods 为 class methods

例子如下:

    module BaseModule
    def self.included(base)
        base.extend(ClassMethods)
    end

    module ClassMethods
        def bar
            puts "class methods"
        end
    end

    def foo
        puts "instance methods"
    end
end

class Test
    include BaseModule
end

# call class method
Test.bar

# call instance method
Test.new.foo

# invalid calls for no method defined
begin
    Test.foo
    Test.new.bar
rescue Exception => e
    puts e
end

参考链接

  1. Class and Instance Methods in Ruby
  2. Include vs Extend in Ruby
  3. Ruby 的 include 和 extend
  4. Mixins in Ruby

Leave a Comment

Your email address will not be published. Required fields are marked *

Loading...