如何在Ruby中的模块中混合一些类方法和一些实例方法?

时间:2014-02-20 19:50:55

标签: ruby mixins

我有一个模块,想把一些方法混合为类方法,一些方法作为实例方法。

例如:

module Foo
  def self.class_method
  end

  def instance_method
  end
end

class Bar
  include Foo
end

用法:

Bar.class_method
Bar.new.instance_method

可以在Ruby中执行此操作吗?

如果没有,是否可以定义哪些方法是类方法,哪些是Bar类中的实例方法?

希望将同一方法定义为类和实例方法。

3 个答案:

答案 0 :(得分:3)

这种模式在Ruby中很常见。事实上,ActiveSupport::Concern很常见,它有点抽象。

您的典型实现如下:

module Foo
  def self.included(other_mod)
    other_mod.extend ClassMethods
  end

  def instance_method
  end

  module ClassMethods
    def class_method
    end
  end
end

class Bar
  include Foo
end

你不能轻易地完成这项工作,但不幸的是,不会以某种方式将包含的模块分成多个部分。

答案 1 :(得分:3)

你可以,但不太喜欢。这是在一个模块中包含实例和类方法的常见模式。

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

  def instance_method
    puts 'instance'
  end

  module ClassMethods
    def class_method
      puts 'class'
    end
  end
end

class Bar
  include Foo
end

bar = Bar.new
Bar.class_method    #=> 'class'
bar.instance_method #=> 'instance'

答案 2 :(得分:1)

你很亲密。你可能注意到实例方法工作正常。类方法的问题是self => Foo在定义时,因此它不响应Bar。如果您在puts "I'm a module method"中添加第self.class_method行,您会找到

Foo.class_method => "I'm a module method"

这是完成您想要做的事情的简单方法:

module Foo_class
  attr_accessor :cat
  def class_method
    puts "I'm a class method" 
  end
end

module Foo_instance
  def instance_method
    puts "I'm an instance method" 
  end
end

class Bar
  extend Foo_class
  include Foo_instance
end

Bar.class_method        #=> I'm a class method
Bar.cat = "meow"
Bar.cat                 #=> "meow"
Bar.new.instance_method #=> I'm an instance method

我为它添加了一个类实例变量@cat和一个访问器,只是为了表明它是多么容易。

Object#extend非常棒,因为您只需将实例变量和方法添加到模块中,就像使用Object#include混合实例变量和方法一样,extend混合它们在类实例变量和类方法中。你也可以这样做:

bar = Bar.new
bar.extend Foo_class

Foo_class中的实例变量和方法适用于实例bar