我有一个Base
超类和一堆派生类,比如Base::Number
,Base::Color
。我希望能够使用这些子类,就好像我在Fixnum
的情况下继承了Number
一样。
最好的方法是什么,同时让他们对is_a? Base
作出适当的回应?
所以,我应该可以做到
Number.new(5) + Number.new(6) # => 11
Number.new.is_a? Base # => true
我想我可以混入Base,并覆盖is_a?,kind_of?和instance_of?方法,但希望有一种更清洁的方式。
答案 0 :(得分:13)
使用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
答案 1 :(得分:3)
为什么你坚持使用is_a?/ kind_of?什么时候response_to?检查事物是一种更清洁的方式吗?您希望对象实现一个接口/契约,而不是任何任意选择的超类的子类。但也许我在这里缺少某种要求。
编辑:我理解你的推理,但它往往会导致糟糕的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?会限制您在单元测试时使用模型对象的能力。即使对于中等复杂的代码,这也是一个很大的问题。
答案 2 :(得分:1)
如果你有完全不相关的类,比如“Number”和“Color”都是从同一个基类派生的,那么我认为你正在使用继承错误。如果他们确实需要访问相同的例程(我不确定他们为什么会这样做),我会使用组合。
答案 3 :(得分:1)
Ruby相当于多重继承是mixins。听起来我觉得你想要的是Base是一个混合到几个类的模块。