扩展内置类是否适合Ruby风格?

扩展内置类是否适合Ruby风格?,ruby,Ruby,我意识到这个问题对于StackOverflow来说可能太过哲学化,但我想知道baseclassing内置类以扩展其功能是否被认为是“好的”Ruby风格 例如 等级

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

例如

等级
现在,Grades对象在构建时看起来像数组,但具有我想要访问的附加sum和avg函数。不使用基类数组,而是将此功能添加到通用对象,这样会“更好”吗?

是的

一般来说,每个人都可以在Ruby中自由地“修补”一切,从您编写的类到比您编写的更重要的类,再到库类

然而,一般计算风格的指导原则是,如果你的类什么都做,它什么也不做。您的示例可以高效地访问
each()
length()
,但您的新
Grades
类现在公开了每个
Array
方法,包括您可能不希望调用的方法,以及某些笨蛋可能有一天会使用的方法!因此,如果你的<代码>等级类是非常公开的(用于整个程序),你可能需要考虑委派。


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

对于这种情况,我认为子类化并不合适。子类应该是其超类的一个更具体的版本,例如,
Fixnum
是一种特定的
Integer
(它是一个以特定方式存储的小整数),它是一种特定的
Numeric
(只有一些数字是整数),是一种特定的
对象
(只有表示数字的对象才是数字)。另一方面,你的
等级
类与
数组
完全等价,只是它可以计算更多关于自身的东西

例如,如果
Grades
限制了它存储的数据,那么它只允许您插入介于0.0和1.0之间的数字(或介于0和100之间的整数,如果您愿意的话)-子类
数组
可能有意义。另一方面,直接将
等级
子类
对象
保留在
数组
属性中也可能有意义

另一方面,添加
sum
avg
,只需添加对其他类型的数组同样有用的功能。对于这种通用功能,我只需将这些方法添加到
数组
,这样您就不必担心在数组中是否有普通的
数组
等级
一个特定的地方


这里有一些灰色区域,当然,如果你建议添加一个
字母
方法来将成绩转换为a到F的成绩字母,我不会那么不愿意将
成绩
分为子类。这肯定是一个判断。但对于这种一般性水平,我真的认为分为子类是不合适的。

Ruby,道德是更自由的。程序员认为这是允许的。事实上,对现有类进行猴子补丁几乎是标准做法。除了其他两个答案所说的,让我让你注意Ruby 2.0
refine
特性,它允许你在更严格的边界内进行猴子补丁,而不必担心任何问题与其他代码的不良交互


但在您的特殊情况下,我认为您创建一个单独的类
Grades
的决定可能是正确的。这只是一种直觉,我必须熟悉您的代码库才能确定。您是否将
Grades
类作为
Array
的子类,或者是否只给出它是一个属性
@grade\u array
,您将在其中存储实际的成绩,并将
array
类中所需的方法委托给该属性。

inb4有人指出,上面的示例并非严格意义上的“猴子补丁”。这将添加.sum()和.avg()直接到数组。相同的区别…谢谢!非常有用的指导原则。这是扩展类的“正确方法”,但不是真正的monkey patching。monkey patching将在基类上重新定义现有方法的功能,而不创建新类型。基本上类似于生成Array.each()做一些不同的事情。你在这里做的不是多态性,而是继承,是OOP的基础。我一直认为monkey patching专门指的是
alias_方法:meth_orig,:meth;def meth()foo;meth_orig end
模式。很高兴知道。@numbers1311407这是一种特殊的猴子补丁形式,您仍然希望能够访问原始功能。这种特殊的技术也应该(谢天谢地)Ruby 2的
prepend
不再需要了。对于主观/风格的问题,可能是一个更好的地方。我认为在这种情况下,最好只使用monkey patch
数组本身。
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