不在每个 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
。当您想挫败 Foo
对 encapsulation 的尝试的作者时,这很有用。
如果我没说清楚,我在这里展示的例子是你应该不做的。当需要对 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 方法),这将特别有用。
我在编写漂亮的代码时遇到了问题。基本上,如果我定义一个根本不会被实例化的 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
。当您想挫败 Foo
对 encapsulation 的尝试的作者时,这很有用。
如果我没说清楚,我在这里展示的例子是你应该不做的。当需要对 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 方法),这将特别有用。