2009-07-07 14 views
6

Ich habe eine Base Superklasse und eine Reihe von abgeleiteten Klassen, wie Base::Number, Base::Color. Ich würde gerne in der Lage sein, diese Kind Klassen zu verwenden, als ob ich sie geerbt hätte von Fixnum im Fall von Number.Vererbung der Klassenvererbung in Ruby

Was ist der beste Weg, dies zu tun, während sie immer noch angemessen auf is_a? Base reagieren?

So sollte ich in der Lage sein

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

zu tun, ich denke, ich Basis in Mischen konnte, und überschreiben die is_a ?, kind_of? und instance_of? Methoden, aber hoffentlich gibt es einen saubereren Weg.

Antwort

13

Das ist eigentlich ganz einfach mit 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

oh wow, ich wusste nicht, is_a? reagierte für Mixins "wahr", und es funktioniert sogar, wenn das enthaltene Modul ein anderes Modul enthält! Ich werde das dann wohl nutzen, anstatt weiterleiten zu können. Vielen Dank! – cloudhead

+1

Tippfehler: sollte 'world = Stringy.new (" Welt ") sein – rampion

1

Ich denke, Sie verwenden die Vererbung falsch, wenn Sie völlig unabhängige Klassen wie "Number" und "Color" alle von der gleichen Basisklasse abgeleitet haben. Ich würde stattdessen Komposition verwenden, wenn sie Zugriff auf die gleichen Routinen benötigen (nicht sicher, warum sie das tun würden).

+0

der Punkt ist, dass sie nicht unabhängig sind, haben sie Funktionalität geteilt und ich brauche sie alle als Basis anerkannt werden, gegen andere Arten Rubin Daten. – cloudhead

+1

Zahlen und Farben sind in der Tat nicht verwandt. Vererbung ist eine "ist-a" -Beziehung, keine "hat-a". Verwenden Sie die Komposition. –

+0

Bei der Vererbung geht es nicht darum, verschiedene Hilfsfunktionen zu bündeln. –

3

Warum bestehen Sie darauf, is_a?/Kind_of? wenn antwort_to? ist eine viel sauberere Art, Dinge zu überprüfen? Sie möchten, dass Objekte eine Schnittstelle/einen Vertrag implementieren, um keine Unterklasse einer beliebig gewählten Oberklasse zu sein. Aber vielleicht fehlt mir hier irgendeine Anforderung.

Bearbeiten: Ich verstehe Ihre Argumentation, aber es führt oft zu schlechten OO/dynamisches Design. Entweder du tust so etwas wie diese, die eine akzeptable Idee in Blattklassen sein könnten, aber in einem Rahmen sollte mit Vererbung gelöst werden:

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

oder etwas ähnliches:

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

Ich denke, dass lassen Code mit Fehler nicht verstehen Ausnahme in der Nachricht übergeben basierte Sprache ist eine perfekte Design-Entscheidung.

Als ein zusätzliches Problem, mit is_a? anstelle von respond_to? schränkt Ihre Fähigkeit ein, Mock-up-Objekte beim Komponententest zu verwenden. Was selbst für mäßig komplizierten Code ein ziemlich großes Problem sein kann.

+2

respond_to? ist nicht immer sauberer, es reagiert nicht auf eine Methode, die auf alle anderen Anrufe reagiert, die Sie später an diese senden. In diesem Fall ist es besser, einmal zu prüfen, ob der Typ korrekt ist. – cloudhead

1

Ruby entspricht der Mehrfachvererbung von Mixins. Es klingt für mich wie, was Sie wollen, ist für Base ein Modul, das in mehrere Klassen gemischt wird.

+0

ja, ich wusste nicht, dass die enthaltenen Module sich wie Superklassen in Bezug auf is_a verhalten würden? - das macht es so gut wie kein Problem – cloudhead

Verwandte Themen