【问题标题】:Multiple-Inheritance type class inheritance in rubyruby中的多继承类型类继承
【发布时间】:2010-11-08 20:55:19
【问题描述】:

我有一个Base 超类和一堆派生类,例如Base::NumberBase::Color。在Number 的情况下,我希望能够使用这些子类,就好像它们是从Fixnum 继承的一样。

最好的方法是什么,同时仍然让他们适当地回复is_a? Base

所以,我应该可以做到

Number.new(5) + Number.new(6) # => 11
Number.new.is_a? Base         # => true

我想我可以混入 Base 并覆盖 is_a?, kind_of?和instance_of?方法,但希望有更清洁的方法。

【问题讨论】:

    标签: ruby oop inheritance


    【解决方案1】:

    这实际上使用 Ruby 非常简单:

    module Slugish
      attr_accessor :slug
      def loud_slug
        "#{slug}!"
      end
    end
    
    class Stringy < String
      include Slugish
    end
    
    class Hashy < Hash
      include Slugish
    end
    
    hello = Stringy.new("Hello")
    world = Stringy.new("World")
    
    hello.slug = "So slow"
    world.slug = "Worldly"
    
    hello.loud_slug      #=> "So slow!"
    world.loud_slug      #=> "Worldly!"
    
    hello.is_a?(Slugish) #=> true
    world.is_a?(Slugish) #=> true
    
    "#{hello} #{world}"  #=> "Hello World"
    
    stuff = Hashy.new
    stuff[:hello] = :world
    stuff.slug = "My stuff"
    stuff.loud_stug      #=> "My stuff!"
    stuff.is_a?(Slugish) #=> true
    

    【讨论】:

    • 哇哦,我不知道is_a?为 mixins 回复了true,如果包含的模块包含另一个模块,它甚至可以工作!那时我可能会使用它,而不是可转发的。谢谢!
    • 错字:应该是world = Stringy.new("World")
    【解决方案2】:

    你为什么坚持使用 is_a?/kind_of?什么时候响应?是一种更清洁的检查方式吗?您希望对象实现一个接口/契约,而不是任何任意选择的超类的子类。但也许我在这里遗漏了某种要求。

    编辑:我理解您的推理,但这通常会导致糟糕的 OO/动态设计。要么你正在做这样的事情,这在叶类中可能是一个可以接受的想法,但在框架中应该通过继承来解决:

    if a.is_a?(something)
       #do something
    elif a.is_a?(something_else)
       #do something else
    ...
    

    或类似的东西:

    if !a.is_a?(something)
       #raise condition/return null/etc.
    endif 
    ...

    我认为在基于消息传递的语言中让代码因不理解异常而失败是一个完美的设计决策。

    另外一个问题是,使用 is_a? 而不是 respond_to? 会限制您在单元测试时使用模型对象的能力。即使对于中等复杂的代码,这也可能是一个相当大的问题。

    【讨论】:

    • respond_to?并不总是更干净,并不是因为它响应一种方法,它会响应您之后发送给它的所有其他调用。因此,在这种情况下,最好检查一次类型是否正确。
    【解决方案3】:

    如果您有完全不相关的类(例如“Number”和“Color”)都派生自同一个基类,我认为您使用继承不正确。如果他们确实需要访问相同的例程(不知道为什么会这样做),我会改用组合。

    【讨论】:

    • 重点是它们并非无关,它们具有共享功能,我需要将它们全部识别为 Base,而不是其他 ruby​​ 数据类型。
    • 数字和颜色确实无关。继承是一种“is-a”关系,而不是“has-a”。使用组合。
    • 继承不是将各种辅助函数捆绑在一起。
    • 和 String 和 Fixnum 也不相关,但它们都继承自 Object。多么奇怪!
    • @ed 我会冷静下来回答这个问题。他可能正在做一些违反您的 OO 原则(也许也违反了我的原则)的事情,但我们没有足够的信息来确定这一点,所以我坚持只是向他展示 Ruby 在这方面的能力并让它​​保持不变。跨度>
    【解决方案4】:

    Ruby 相当于多重继承的是 mixins。在我看来,您希望 Base 成为一个混合到多个类中的模块。

    【讨论】:

    • 是的,我不知道包含的模块在 is_a 方面会表现得像超类? - 这几乎使它成为一个非问题
    猜你喜欢
    • 2020-08-31
    • 1970-01-01
    • 2013-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多