【问题标题】:Ruby: Is it possible to define a class method in a module?Ruby:是否可以在模块中定义类方法?
【发布时间】:2011-06-09 14:51:58
【问题描述】:

假设有三个类:AB & C。我希望每个类都有一个类方法,比如self.foo,它的代码与ABC 完全相同。

是否可以在一个模块中定义self.foo 并将该模块包含在ABC 中?我尝试这样做并收到一条错误消息,指出无法识别foo

【问题讨论】:

  • Ruby 并没有静态方法的概念。在 ruby​​ 中,所有方法都有一个接收器对象。它只是可能是一个恰好有classClassModule 的方法。

标签: ruby


【解决方案1】:

只是想扩展奥利弗的答案 在一个模块中同时定义类方法和实例方法。

module Foo
 def self.included(base)
   base.extend(ClassMethods)
 end
 module ClassMethods
   def a_class_method
     puts "ClassMethod Inside Module"
   end
 end

 def not_a_class_method
   puts "Instance method of foo module"
 end
end

class FooBar
 include Foo
end

FooBar.a_class_method

FooBar.methods.include?(:a_class_method)

FooBar.methods.include?(:not_a_class_method)

fb = FooBar.new

fb.not_a_class_method

fb.methods.include?(:not_a_class_method)

fb.methods.include?(:a_class_method)

【讨论】:

    【解决方案2】:

    这是使 ruby​​ 如此特别的基本 ruby​​ mixin 功能。 extend 将模块方法转换为类方法,include 将模块方法转换为包含/扩展类或模块中的实例方法。

    module SomeClassMethods
      def a_class_method
        'I´m a class method'
      end
    end
    
    module SomeInstanceMethods
      def an_instance_method
       'I´m an instance method!'
      end
    end
    
    class SomeClass
      include SomeInstanceMethods
      extend SomeClassMethods
    end
    
    instance = SomeClass.new
    instance.an_instance_method => 'I´m an instance method!'
    
    SomeClass.a_class_method => 'I´m a class method'
    

    【讨论】:

    • 感谢您展示includeextend 之间的区别。
    【解决方案3】:

    Rails 3 引入了一个名为 ActiveSupport::Concern 的模块,其目标是简化模块的语法。

    module Foo
      extend ActiveSupport::Concern
    
      module ClassMethods
        def some_method
          # stuff
        end
      end
    end
    

    它允许我们在模块中保存几行“样板”代码。

    【讨论】:

      【解决方案4】:
      module Common
        def foo
          puts 'foo'
        end
      end
      
      class A
        extend Common
      end
      
      class B
        extend Common
      end
      
      class C
        extend Common
      end
      
      A.foo
      

      或者,您可以在之后扩展类:

      class A
      end
      
      class B
      end
      
      class C
      end
      
      [A, B, C].each do |klass|
        klass.extend Common
      end
      

      【讨论】:

      • 在这种情况下foo不是A、B、C的实例方法吗?
      • 正如 Andrew 已经指出的,Ruby 的方法总是实例方法。但在这种情况下,实例就是类。所以,foo 是类实例方法。你用类作为接收者来调用它:A.foo。在 A 的实例方法中,您还可以使用 self.class.foo
      • @MladenJablanović 好吧,instance 通常用于指代类生成的对象,而不是类对象本身。我建议将它们称为 类方法 而不是 类实例方法 以避免混淆。
      • 也许值得一提的是class A; extend Common; end 等同于class A; singleton_class.include Common; end
      【解决方案5】:

      是的

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

      我应该添加一个可能的注释 - 如果模块将是所有类方法 - 最好在模型中使用 extend ModuleName 并直接在模块中定义方法 - 而不是在模块中使用 ClassMethods 模块, 啦啦

       module ModuleName
         def foo
           # stuff
         end
       end
      

      【讨论】:

        猜你喜欢
        • 2010-09-13
        • 2021-09-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-01
        • 1970-01-01
        • 2017-05-29
        相关资源
        最近更新 更多