使用多级继承代替ruby mixins

vis*_*nth 6 ruby oop inheritance mixins

这是红宝石中多级继承的示例,这里有3个类A,B和C。B继承自A,C继承自B,因此最后,类C具有A,B和C的所有方法。

class A
  def hello_by_a
    puts "A says hello"
  end
end

class B < A
  def hello_by_b
    puts "B says hello"
  end
end

class C < B
  def hello_by_c
    puts "C says hello"
  end
end

c = C.new
c.hello_by_a #=> A says hello
c.hello_by_b #=> B says hello
c.hello_by_c #=> C says hello

p c.methods-Object.methods #=> [:hello_by_c, :hello_by_b, :hello_by_a]
Run Code Online (Sandbox Code Playgroud)

这和mixin一样,这里不是类A和B,而是包含了模块A和B,它们已包含在类C中。现在,类C具有所有3种方法

module A
  def hello_by_a
    puts "A says hello"
  end
end

module B
  def hello_by_b
    puts "B says hello"
  end
end

class C
  include A
  include B

  def hello_by_c
    puts "C says hello"
  end
end

c = C.new

c.hello_by_a #=> A says hello
c.hello_by_b #=> B says hello
c.hello_by_c #=> C says hello

p c.methods-Object.methods #=> [:hello_by_c, :hello_by_b, :hello_by_a]
Run Code Online (Sandbox Code Playgroud)

最后,如果我们用两种方式都做到这一点,则类C将拥有类A和B或模块A和B的所有方法。那么,为什么最好使用模块而不是对类进行多级继承呢?

我知道我们应该使用mixins,但是真的不知道为什么我们不应该像上面那样使用多级继承。有什么缺点和优点。有没有

Jör*_*tag 6

两个主要原因:

您只能从一个类继承,但是可以根据需要混合任意数量的mixins。这意味着从某种意义上说,继承是极其“昂贵的”,如果您被迫使用继承,则被迫“消耗” 100%的“继承资源”。

您可以根据需要任意组合mixins。在您的示例中,我只能获取的方法A,的方法AB和的方法ABC。例如,我不能仅获得的方法B。随着混入,我可以在任何组合撰写他们:只有A,只有B,只有CABACBCABC。我还可以按任意顺序组合它们:我可以使用C覆盖方法的方法,B也可以使用B覆盖方法的方法C

我可以轻松地想象一个同时为Enumerable和的对象Comparable。(例如,Strings是Ruby 1.9之前的版本Comparable在Ruby 1.9之前也是如此Enumerable。)在您建议的世界中,只有Enumerable从继承ComparableComparable从继承才有可能Enumerable。但是,这将不起作用:Numerics是Comparable但不是EnumerableArrays是Enumerable但不是Comparable

还有一个更哲学/语义上的原因:可枚举性可比性是完全正交的概念,为什么它们如此紧密地结合在一起?继承是我们拥有的最接近的耦合形式之一,将两个实际上彼此之间没有任何关系的概念紧密地联系在一起是错误的