3

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

例如

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 函数。不是基类数组而是将此功能添加到通用对象会是“更好”的样式吗?

4

3 回答 3

8

是的。

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

然而,一般的计算风格指南是,如果你的类什么都做,它什么也不做。您的示例可以有效地访问,each()但是的新类现在公开了每个方法,包括您可能不想调用的方法 ~ 以及某些白痴可能有一天会去猴子补丁的方法!因此,如果您的课程非常公开(被整个程序使用),您可能需要考虑委托。length()Grades ArrayGrades

另一个准则——在某些语言中比在其他语言中更适用——是你永远不应该继承,除非你重写一个方法,以实现多态性。包括我在内的整个 Ruby 社区都喜欢自由打破的另一条规则。

于 2013-05-12T05:09:59.863 回答
4

对于这种情况,我会说子类化并不合适。一个子类应该是它的超类的一个更具体的版本——例如,Fixnum它是一种特定的类型Integer(它是以特定方式存储的一个小整数),它是一种特定的类型Numeric(只有一些数字是整数),它是一种特定的排序Object(只有表示数字的对象是数字)。Grades另一方面,你的类完全等价于一个,Array除了它可以计算更多关于它自己的东西。

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

另一方面,添加sumandavg只是添加对其他类型的数组同样有用的功能。对于这样的通用功能,我会简单地将这些方法添加到,Array这样您就不必担心您是否有一个平原ArrayGrades一个特定的地方。

当然,这里有一些灰色区域——如果您提议添加一种letter将成绩转换为 A 到 F 等级字母的方法,我不会那么不愿意使用 subclass Grades。这绝对是一个判断电话。但是对于这种级别的通用性,我真的不认为子类化是合适的。

于 2013-05-12T05:31:39.263 回答
0

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

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

于 2013-05-12T12:37:41.763 回答