ruby – “扩展自我”是实用程序模块的反模式吗?

史蒂夫·克拉夫尼克(Klabnik)最近在 pull request年的一个实用模块中说:

[The code] obscures the fact that these are class methods,and we
want to use them that way. Plus,I think that extend self is generally
an anti-pattern,and shouldn’t really be used except in some cases. I
thought about it,and I think this is one of those cases.

>创建实用程序模块(例如,为数学)时,声明方法的最佳方式是什么?
>什么时候扩展自我成语呢?

解决方法

他不会说1)为什么他认为这是一种反模式(除了模糊你所定义的课程方式的事实),或者2)为什么,考虑到这一点,这是一个例子他认为不应该使用它,所以很难专门反驳他的任何论点.

但是,我不相信延伸自我是一种反模式.一个实用程序模块似乎是一个很好的例子.我也使用它作为测试夹具的容易存储.

我认为值得研究什么是自我扩展,什么可能存在的问题,以及什么替代方案.

它是核心,它只是一种避免写自己的方式.在模块中的每个方法定义之前,您从未打算混合到一个类中,因此永远不会有自己创建的“实例”,所以可以通过定义只有“类”方法(如果您想要能够调用他们,就是).

它是否掩饰了您打算将方法用作类方法的事实?嗯,是的,如果你不看文件的顶部,它说,扩展自己,这是可能的.不过,我会认为,如果你有可能使这个混乱,你的课程可能太复杂了.

从你的班级 – 从它的名字和内容来看,它应该是很明显的 – 它是作为一个效用函数的集合.理想情况下,它不会比屏幕高出多少,所以延长自我几乎永远不会看不见.正如我们将看到的,替代品也遭受几乎完全相同的问题.

一种替代方案是使用类<<自己这样:

module Utility
  class << self
    def utility_function1
    end
    def utility_function2
    end
  end
end

我不是这个的粉丝,尤其是因为它引入了一个额外的缩进层.这也很丑(完全主观,我知道).它同样也遇到与“定义类”方法完全相同的问题.

您也可以使用此方法来定义类之外的实例方法<<自我阻挡 - 这可能导致这样的诱惑(尽管我希望它不会),所以我认为延长自我在这方面是优越的,消除了这种混乱的可能性. (当然,使用def self.utility_function的“长手”风格也是一样的.) 另一种方法可能是使用单例对象.我不认为这是一个好主意,因为一个单身对象是一个对象的原因 – 它的意图是保持状态和做事情,而且也是唯一存在的对象.这对于一个实用程序模块来说根本没有意义,它应该是一系列独立的无状态函数.你不希望MathUtils.cos(90)根据MathUtils的内部状态返回一个不同的值,对吧? (我知道你当然可以在一个模块中执行所有这些操作,但是对于我来说,它比一个技术方面更符合语义划分). 它也导致了同样的问题,可以说是模糊了这个方法被称为类方法(类)的事实.它们被定义为实例方法,并将它们称为实例方法,但首先通过调用方法实例获取类的单个实例.

class MathSingleton
  include Singleton

  def cos x
  end
end

MathSingleton.instance.cos x

为了这个目的,这将是一个可怕的替代方案.但是,看来,唯一表明这些方法将被用作单例实例的方法的只是一行刚刚在顶端,就像扩展自身一样.

那还有什么其他可能的缺点呢?我不知道有什么,但如果有其他人,我有兴趣听到他们.

我会认为,扩展自我导致更短的代码,从而避免了无关的自我,并允许您专注于其方法名称和含义.

它还有一个很好的属性,如果你正在编写另一个使用很多实用功能的类,例如,你可以混合它们,并且它们将可用,而不必每次使用模块名称.很像静态导入工作在其他语言.

相关文章

validates:conclusion,:presence=>true,:inclusion=>{...
一、redis集群搭建redis3.0以前,提供了Sentinel工具来监控各...
分享一下我老师大神的人工智能教程。零基础!通俗易懂!风趣...
上一篇博文 ruby传参之引用类型 里边定义了一个方法名 mo...
一编程与编程语言 什么是编程语言? 能够被计算机所识别的表...
Ruby类和对象Ruby是一种完美的面向对象编程语言。面向对象编...