Ruby 是";“扩展自我”;实用模块的反模式?

Ruby 是";“扩展自我”;实用模块的反模式?,ruby,Ruby,史蒂夫·克拉布尼克(Steve Klabnik)最近在一篇关于实用模块的文章中说: [代码]掩盖了这是类方法的事实,我们 我想这样使用它们。另外,我认为extend self通常是 一个反模式,除了在某些情况下,不应该真正使用。我 想想看,我认为这就是其中之一 创建实用程序模块(例如,数学)时,声明方法的最佳方式是什么 “扩展自我”这个成语什么时候合适 他不说1)为什么他认为这是一种反模式(除了掩盖你正在定义类方法的事实)或者2)为什么,经过思考,这是他认为不应该使用的情况之一,这并没有什么帮

史蒂夫·克拉布尼克(Steve Klabnik)最近在一篇关于实用模块的文章中说:

[代码]掩盖了这是类方法的事实,我们 我想这样使用它们。另外,我认为
extend self
通常是 一个反模式,除了在某些情况下,不应该真正使用。我 想想看,我认为这就是其中之一

  • 创建实用程序模块(例如,数学)时,声明方法的最佳方式是什么
  • “扩展自我”这个成语什么时候合适

他不说1)为什么他认为这是一种反模式(除了掩盖你正在定义类方法的事实)或者2)为什么,经过思考,这是他认为不应该使用的情况之一,这并没有什么帮助,所以很难具体反驳他的任何论点

然而,我不认为
扩展self
是一种反模式。实用模块似乎是它的用例的一个很好的例子。我还将其用作测试夹具的简易存储

我认为有必要检查什么是
extend self
,它可能存在哪些问题,以及有哪些替代方案

从本质上讲,它只是一种避免在模块中的每个方法定义之前编写
self.
的方法,而这些方法定义从来都不打算混合到类中,因此永远不会创建自身的“实例”,因此根据定义只能有“类”方法(如果您希望能够调用它们,也就是说)

它是否掩盖了您打算将这些方法用作类方法的事实?好的,是的,如果您不查看文件顶部的
extend self
,这是可能的。然而,我想说的是,如果你有可能造成这种混乱,你的课程可能太复杂了

从类的名称和内容可以明显看出,它是实用函数的集合。理想情况下,它不会超过一个屏幕那么高,所以
extend self
几乎永远不会消失在视线之外。正如我们将看到的,替代方案也面临着几乎完全相同的问题


另一种选择是使用
class实用程序模块,而不是mixin,它是包装常量和方法的容器,其中包含一些常见问题。混合,比如这个

module SingingCapability
  def sing; puts "I'm singing!" end
end

Human = Class.new
Fred = Human.new.tap { |o| o.extend SingingCapability }
通常对其包含者提出一些要求。也就是说,通常只有某些对象是包含或扩展给定mixin的好候选对象。假设,一个模块可能同时是一个实用模块和一个mixin。如果模块本身属于需要扩展的合格候选模块,那么继续扩展它

总而言之,我确实认为这不是一个很好的实践,但Ruby在这一点上对我提出了挑战,因为我们甚至有
Module#Module_函数
方法来促进这种弊端:

module SingingBox
  def sing; "Tralala!" end
  module_function :sing
end

SingingBox.sing #=> "Tralala!"

有一个例子说,在这里使用module_函数更合适,他是绝对正确的。对象不必是模块就可以是“实用程序模块”。如果决定在特定名称空间(即
Module
instance)下收集实用程序方法,则该
Module
实例不应自动成为使用这些实用程序扩展的对象。这些基本上是正交的考虑因素,实用方法应该存储在专用模块(如果有的话)中,它们应该成为哪个对象的单例方法。我认为这个问题太主观了,我很难看到客观的答案。我投票决定关闭。你的例子似乎不适用于实用模块。通过命名模块SingingCapability,您自然会尝试将其与将拥有该功能的某些对象相关联。公用事业公司不会这样做。实用程序是供每个人使用的,不属于某个实例的属性。再想一想,你实际上是对的。我为mixin命名,而不是实用模块。我想我应该把答案完全重做一遍。非常感谢这个深思熟虑的答案。
module SingingCapability
  def sing; puts "I'm singing!" end
end

Human = Class.new
Fred = Human.new.tap { |o| o.extend SingingCapability }
module SingingBox
  def sing; "Tralala!" end
  module_function :sing
end

SingingBox.sing #=> "Tralala!"