不在每个 class 方法中使用 self 并且不在 ruby 中使用单例模型

Not use self in every class method and not use singleton model in ruby

我在编写漂亮的代码时遇到了问题。基本上,如果我定义一个根本不会被实例化的 class,我会做这样的事情:

class Foo
  def self.bar
    # Do something
  end
end

但是这个语法让我很困扰(必须在每个方法中放入 self.),所以单例解决了我的问题:

class Foo
  class << self
    def bar
      # Do something, but in better code
    end
  end
end

两种方式我都可以做 Foo.bar 并且它会做一些事情,但是第一个看起来不太好,第二个我仍然不明白单例是如何工作的,所以更好小心不要使用它。

所以,最后... 我想问的是:除了上面提到的,还有什么方法可以做到Foo.bar

这是我在评论中提到的一种深奥的元编程技术的示例:

module Foo
  instance_eval do
    def bar
      'baz'
    end
  end
end

现在调用新方法:

Foo.bar
=> 'baz'

instance_eval 的用途是 unintuitive 因为它用于定义 class 方法,而 class_eval 是实例方法。

Cary 提到的技术有一个类似的方法(尽管他使用 define_method 例如方法,而 define_singleton_method 用于 class 方法):

module Foo
  define_singleton_method(:bar) do
    'baz'
  end
end

调用方法是一样的:

Foo.bar
=> 'baz'

但同样,这些是您永远不会以这种方式使用的高级技术,因为有更简单的标准方法可以完成相同的任务(并且您在问题中给出了两个示例)。如果您尝试以这种方式定义所有 class 方法,那么任何阅读它的人都会感到丑陋、重复和困惑。

显示的技术通常由 定义的 module/class 之外的代码使用,这样您就可以在外部操作它而不必直接修改它的源代码,有时简称monkey patching.

例如,如果模块没有定义任何方法:

module Foo
end

您可以在其他代码中的任何其他地方说 Foo.instance_eval {}Foo.define_singleton_method(:bar) {},此后它将应用于 Foo。当您想挫败 Fooencapsulation 的尝试的作者时,这很有用。

如果我没说清楚,我在这里展示的例子是你应该做的。当需要对 classes/modules 进行动态更改时使用它们。那不是你描述的。

已经提到过)

您可以使用包含您的 class 方法的模块扩展您的 class(该模块可以嵌套在您的 class 中):

class Foo
  module ClassMethods
    def bar
      # Do something
    end
  end

  extend ClassMethods
end

你也可以把它移到你的 class 之外,甚至是在它自己的文件中(这在结构方面很有用,或者如果有 很多 class 方法):

# foo/class_methods.rb
class Foo
  module ClassMethods
    def bar
      # Do something
    end
  end
end

# foo.rb
class Foo
  extend ClassMethods
end

通过 extend 定义的方法甚至可以在基础 class:

中被覆盖
class Foo
  module ClassMethods
    def bar
      123
    end
  end
end

class Foo
  extend ClassMethods

  def self.bar
    super * 2
  end
end

Foo.bar #=> 246

如果您想在使用同一模块扩展多个 class 时添加自定义功能(考虑共享 class 方法),这将特别有用。