论坛首页 编程语言技术论坛

玩转Ruby系列:给Ruby类Mixin进Class method

浏览 3845 次
精华帖 (0) :: 良好帖 (2) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-09-17   最后修改:2009-09-17

Ruby是靠mixin来实现多重继承的,mixin的module中的方法在类中可以被调用,就像类自己的方法一样,但这只局限于instance method,module中的class method是没法在class中直接当做类方法来调用的。

module TestModule
  def instance_method
    puts "this is a instance method in module"
  end
  
  def self.class_method
    puts "this is a class method in module"
  end
end

class TestClass
  include TestModule
  
end

TestClass.new.instance_method 
#=> this is a instance method in module
TestClass.class_method 
#=> undefined method `class_method' for TestClass:Class (NoMethodError)

 但是灵活的Ruby还是又办法给类mixin类方法的

module TestModule
  
  def self.included(recipient)
    recipient.extend(ModelClassMethods)
  end

  module ModelClassMethods
    def class_method
      puts "this is a class method in module"
    end
  end # class methods

end

class TestClass
  include TestModule
  
end

TestClass.class_method
#=> this is a class method in module

 其实instance method 也可以通过这种方法mixin,所以有人喜欢用这样的Mixin Template

module TestModule
  
  def self.included(recipient)
    recipient.extend(ModelClassMethods)
    recipient.class_eval do
      include ModelInstanceMethods
    end
  end

  module ModelClassMethods
    def class_method
      puts "this is a class method in module"
    end
  end # class methods

  module ModelInstanceMethods
    def instance_method
      puts "this is a instance method in module"
    end
  end # instance methods
end

class TestClass
  include TestModule
  
end

TestClass.new.instance_method 
#=> this is a instance method in module
TestClass.class_method  
#=> this is a class method in module
   发表时间:2009-09-17  
用extend不是就可以吗?
irb(main):001:0> module TestModule
irb(main):002:1> def class_method
irb(main):003:2> puts 'class_method'
irb(main):004:2> end
irb(main):005:1> end
=> nil
irb(main):006:0> class TestClass
irb(main):007:1> extend TestModule
irb(main):008:1> end
=> TestClass
irb(main):009:0> TestClass.class_method
class_method
=> nil
irb(main):010:0> 
0 请登录后投票
   发表时间:2009-09-17  
yuan 写道
用extend不是就可以吗?
irb(main):001:0> module TestModule
irb(main):002:1> def class_method
irb(main):003:2> puts 'class_method'
irb(main):004:2> end
irb(main):005:1> end
=> nil
irb(main):006:0> class TestClass
irb(main):007:1> extend TestModule
irb(main):008:1> end
=> TestClass
irb(main):009:0> TestClass.class_method
class_method
=> nil
irb(main):010:0> 

是的,我是看到一段源码是这样写的,这事mixin的一个模板,实例方法也可以这样mixin
0 请登录后投票
   发表时间:2009-09-17   最后修改:2009-09-17
用extend不是就可以吗?
irb(main):001:0> module TestModule
irb(main):002:1> def class_method
irb(main):003:2> puts 'class_method'
irb(main):004:2> end
irb(main):005:1> end
=> nil
irb(main):006:0> class TestClass
irb(main):007:1> extend TestModule
irb(main):008:1> end
=> TestClass
irb(main):009:0> TestClass.class_method
class_method
=> nil
irb(main):010:0> 

+100
0 请登录后投票
   发表时间:2009-09-17   最后修改:2009-09-17
include是个语法(用1.class.methods.grep /include/ 不到),而extend是个方法(所有类或实例都有,因为是是根类Object的实例方法,见api:http://www.ruby-doc.org/core/classes/Object.html#M000335),用来给当前对象加载模块里的方法作为实例方法,如果当前对象是个类,那么就是成为类方法,如果是实例,那么就是实例方法:

irb(main):001:0> class C1
irb(main):002:1> end
=> nil
irb(main):003:0> module M1
irb(main):004:1> def foo
irb(main):005:2> puts "bar"
irb(main):006:2> end
irb(main):007:1> end
=> nil
irb(main):008:0> C1.foo
NoMethodError: undefined method `foo' for C1:Class
	from (irb):8
irb(main):009:0> C1.extend M1
=> C1
irb(main):010:0> C1.foo
bar
=> nil
irb(main):011:0> C1.new.foo
NoMethodError: undefined method `foo' for #<C1:0xb79b3f04>
	from (irb):11
irb(main):012:0> C1.new.extend(M1).foo
bar
=> nil
irb(main):013:0> 
0 请登录后投票
   发表时间:2009-09-17  
我现在开始不喜欢 acts_as_XXX 这种扩展方式了,写起来太累,用起来也没有方便太多。
0 请登录后投票
   发表时间:2009-09-18  
rainchen 写道
include是个语法(用1.class.methods.grep /include/ 不到)


你源码看少了,include 是个私有方法
irb(main):001:0> String.private_methods.include?("include")
=> true


很多的扩展都是这样加载的:
String.send(:include, YourModule)
0 请登录后投票
   发表时间:2009-09-18  
ri Module#include看看就知道了 ruby里很多看似关键字的东西都是方法
0 请登录后投票
   发表时间:2009-09-18   最后修改:2009-09-18
hozaka 写道
rainchen 写道
include是个语法(用1.class.methods.grep /include/ 不到)


你源码看少了,include 是个私有方法
irb(main):001:0> String.private_methods.include?("include")
=> true


很多的扩展都是这样加载的:
String.send(:include, YourModule)



恩,的确是个私有方法
irb(main):001:0> String.private_methods.grep /include/
=> ["included", "include"]


我以为methods是包括了public,protected,private的,现在发现是我想当然了
String.methods.grep /include/
=> ["included_modules", "include?"]

谁叫Object还有个public_methods,private_methods,protected_methods,吃一堑长一智,以后要多看api:
http://www.ruby-doc.org/core/classes/Object.html#M000361
0 请登录后投票
   发表时间:2009-09-18  
orange0513 写道
ri Module#include看看就知道了 ruby里很多看似关键字的东西都是方法


原来是在Module里定义的http://www.ruby-doc.org/core/classes/Module.html#M001638
我在Ojbect里没看到还以为是特殊语法了,差点误人子弟了
0 请登录后投票
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics