是否有适当的Ruby风格来扩展内置类?

时间:2013-05-12 05:04:54

标签: ruby

我意识到这个问题对于StackOverflow来说可能太哲学了,但是我想知道基类化内置类来扩展它们的功能是否被认为是“好的”Ruby风格。

E.g。

class Grades < Array
  def sum
    sum = 0
    self.each do |num|
      sum += num
    end
    return sum
  end
  def avg
    self.sum/self.length
  end
end

现在,Grades对象在构建时看起来像数组,但是具有我想要访问的额外的sum和avg函数。它是“更好”的风格,不是基类数组,而是将此功能添加到通用对象?

3 个答案:

答案 0 :(得分:8)

一般来说,每个人都可以自由地“修补”Ruby中的所有内容,从你编写的类到比你写的更重要的类,到库类。

然而,一般的计算风格指南是,如果你的班级做了所有事情,它什么都不做。您的示例有效地访问each()length()您的新Grades类现在公开每个 Array方法,包括那些你可能不想要的东西〜包括那些有一天可能会有一些cretin和猴子补丁!因此,如果您的Grades课程非常公开(由整个课程使用),您可能需要考虑授权。

另一个指南 - 在某些语言中应用的比其他语言更多 - 是你永远不应该继承的,除非你覆盖一个方法,以实现多态。另一个规则是整个Ruby社区,包括我在内,都喜欢自由自在。

答案 1 :(得分:4)

对于这种情况,我会说子类化并不合适。子类应该是其超类的更具体的版本 - 例如,Fixnum是特定类型的Integer(它是以特定方式存储的小整数),这是特定类型的{{ 1}}(只有一些数字是整数),这是一种特定的Numeric(只有表示数字的对象才是数字)。另一方面,您的Object课程与Grades完全相同,只是它可以计算更多关于自身的内容。

如果Array限制了它存储的数据 - 例如,它只允许你插入0.0到1.0之间的数字(或0到100之间的整数,如果你愿意的话) - 它可能有意义继承Grades。另一方面,直接拥有Array子类Grades也是有意义的,并将实际成绩保持在Object属性中。

另一方面,添加Arraysum只是添加了对其他类型的数组同样有用的功能。对于此类通用功能,我只需将这些方法添加到avg,这样您就不必担心在特定位置是否有普通ArrayArray

当然,这里有一些灰色区域 - 如果您建议添加Grades方法将成绩转换为A到F等级字母,我不会那么不愿意继承{{1} }。这绝对是一个判断。但是对于这种通用性水平,我真的不认为子类化是合适的。

答案 2 :(得分:0)

在Ruby中,道德更自由。允许的是程序员认为的任何东西。实际上,修补现有类的猴子几乎是标准做法。除了其他两个答案所说的之外,让我把你的注意力转移到Ruby 2.0 refine功能上,它允许你在更严格的边界内进行修补,而不用担心与其他代码发生不良的交互。

但在您的特定情况下,我认为您创建单独的类Grades的决定可能是正确的。这只是一种直觉,我必须熟悉您的代码库才能肯定地说出来。不太重要的是,您是否将Grades类设为Array的子类,或者是否只给它一个属性@grade_array,您将在其中存储实际成绩并将其存储到从Array class委派您想要的方法。