【问题标题】:How to mixin some class methods and some instance methods from a module in Ruby?如何在 Ruby 中混合模块中的一些类方法和一些实例方法?
【发布时间】:2014-03-22 00:01:33
【问题描述】:

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

例如:

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 类中定义哪些方法是类方法,哪些是实例方法?

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

【问题讨论】:

    标签: ruby mixins


    【解决方案1】:

    这种模式在 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
    

    不幸的是,如果不以某种方式将包含的模块分成多个部分,您将无法像您描述的那样轻松完成此操作。

    【讨论】:

    • 感谢您将包含的模块拆分为多个部分的说明。我也想知道。
    【解决方案2】:

    你可以,但不完全是这样。这是在一个模块中同时包含实例和类方法的常见模式。

    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'
    

    【讨论】:

      【解决方案3】:

      你很接近。您可能注意到实例方法工作正常。类方法的问题是self => Foo在定义时,所以它不响应Bar。如果你在self.class_method中添加puts "I'm a module 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

      【讨论】:

        猜你喜欢
        • 2017-01-29
        • 1970-01-01
        • 1970-01-01
        • 2011-07-28
        • 1970-01-01
        • 2013-03-24
        • 1970-01-01
        • 1970-01-01
        • 2016-03-03
        相关资源
        最近更新 更多