entwurfsproblem

  • Hallo

    Ich schreibe an einer kleinen music tag lib in java die ich für ein projekt brauch und weiss jetzt nicht was designmässig besser ist.
    Ich habe zur zeit eine abstrakte klasse MusicTag. Von ihr erbt ID3Tag.Von ID3Tag erben ID3v1Tag und ID3v2Tag. Von ID3v1Tag erbt ID3v1_1Tag. Von ID3v2Tag erbt ID3v2_3. Von ID3v2_3 erbt ID3v2_4 Tag. (endlich geschafft)

    Wenn ich dann irgendwann in meinem programm einen Tag (welcher art auch immer) brauch so schreibe ich einfach zb:

    MusicTag mt = new ID3v1Tag(bla);

    und hab dann durch MusicTag zugriff auf alle methoden die relevant für tags sind.
    Jetzt stell ich mir allerdings die frage ob es nicht besser wär ein Interface IMusicTag zu definieren mit den Methoden getArtist(),getAlbum usw...
    Was ist besser, bzw macht es einen Unterschied (ich sehe zur zeit keinen). Hab mir bis jetzt noch nie gedanken über sowas gemacht...

    mfg

  • der unterschied ist dass wenn du ein interface implementierst, MUSST du ALLE funktionen implementieren. wenn du eine abstrakte klasse erweiterst kannst du auch nur n paar (musst also NICHT alle) abstrakten funktionen implementieren. die abgeleitete klasse ist dann wieder abstrakt, solange bis alle funktionen implementiert sind.

    in deinem fall würd ich beides verwenden. schreib ein interface mit all den funktionen die so ein 'MusicTag' haben soll. behalt die 'abstract base class' MusicTag, implementier dort dein grad geschriebenes interface, IMusicTag (wie auch immer). wie gesagt, du musst nur die funktionen implementieren die alle MusicTags gemeinsam haben. die restlichen überlässt du den abgeleiteten Klasse wie ID3Tag, usw. dort implementierst du dann die restlichen abstrakten funktionen und kannst diese klasse dann auch instanzieren.

    zB. IMusicTag mt = new ID3Tag();

    lg

    computer says nooooohhhh!

  • naja, mMn macht in dem fall ein interface genau dann sinn, wenn du möglicherweise irgendwann einmal die impelemntierung der gemeinsamen methoden austauschen musst, oder evtl für einen speziellen tag eine andere implementierung einer gemeinsamen methode brauchst.

    flexibler bist du auf jeden fall wenn du das Interface einführst, selbst wenn du es dann im endeffekt nicht brauchst, gibt es nicht wirklich einen grund es nicht zu haben

    mfg
    s.

    edit: ups hab das "abstrakte" überlesen
    Martinez: man kann allerdings auch methoden in einem interface als abstrakt definieren, dann davon eine abstrakte klasse ableiten, die ebenfalls nur ein paar der methoden implementiert...


  • Martinez: man kann allerdings auch methoden in einem interface als abstrakt definieren, dann davon eine abstrakte klasse ableiten, die ebenfalls nur ein paar der methoden implementiert...

    du willst von einem interface eine abstrakte klasse ableiten? wie geht denn das?
    ausserdem deklariert man eine funktion als abstrakt, definieren kannst du sie ja eben nicht, sonst wär sie ja nicht abstrakt.

    wie auch immer:
    alle funktionen in einem interface sind per definition abstrakt, das keyword wird deshalb meist weggelassen, muss man aber nicht. ändert aber auch nix an der tatsache das ALLE FUNKTIONEN IN EINEM INTERFACE ABSTRAKT SIND!

    computer says nooooohhhh!

  • Es is eigentlich fast immer eine gute Idee, gegen ein Interface zu programmieren, anstatt gegen eine konkrete Implementierung. Mit Interface ist hier aber eine Art der Abstraktion gemeint und nicht das Javaspezifische Konstrukt 'Interface'. In Deinem Fall ist es meiner Meinung nach egal, ob 'MusicTag' jetzt ein Java-Interface oder eine abstrakte Klasse ist: Es stellt in jedem Fall ein gemeinsames Interface dar, d.h. der Client muss, wenn er ein MusicTag verwendet, nicht wissen ob das jetzt ID3v2Tag oder v1 oder sonstwas ist. Gut so! Wenn MusicTag Implementierungsdetails enthaelt, dann verwende die abstrakte Klasse. Wenn nicht, dann ein (Java-)Interface. Beides zu verwenden, also vor die abstrakte Klasse dann noch ein Interface zu schalten, wuerde ich als unnoetig und ueberspezifiziert betrachten.

    Du koenntest vielleicht etwas vorsichtiger/sparsamer mit Vererbung sein. Vererbung ist eigentlich ein recht gefaehrliches Feature, weil eine komplexe Vererbungshirachie den Code oft schwerer zum lesen macht anstatt leichter. Man sollte Vererbung deshalb gezielt und so selten wie nur moeglich einsetzen. Man sie z.B. oft durch Delegation und/oder Komposition ersetzen.
    Wenn Du nicht genau weisst, das Du bald andere Tags als ID3 unterstuetzen wirst, dann lasse die ganze Klasse ID3Tag erstmal weg und tu den Code in MusicTag. Wenn Du dann tatsaechlich mal andere TagTypen unterstuetzen moechtest, dann kannst du immer noch die Vererbungshirachie ausbauen, MusicTag von einer abtrakten Klasse zu einem JavaInterface refactoren, den implementierungscode in eine ID3 Klasse stecken oder was auch immer. Solange sich das Interface der API nicht aendert (getAlbum(), getArtist() usw.), kannst Du in den oberen Klassen Refactoring betreiben wie Du magst, ohne das der Clientcode etwas davon mitbekommt.

  • Danke. Werde das jetzt auch so machen dass ich statt meiner abstrakten klasse ein interface verwende, denn konkreten code enthält sie nicht.

    Ich finde das thema allgemein sehr interessant und bin etwas enttäuscht dass man mir dass im bakk nur so unzureichend nähergebracht hat. Objektorientierte Modellierung war damals ja noch nicht pflicht. Hat das schon wer gemacht und kann es als zb freu/wahlfach empfehlen?

    mfg

  • Soweit ich mich erinnere, ist dieses Design aus verschidenen Gründen, die ich nicht klar erinnere, schwach. So eine Hierarschie von Vererbungen sollte man vermeiden. Weil es ein allgemeines Problem ist, gibt es dazu ein bekanntes Entwurfsmuster: Brückenmuster.

  • Ich finde das thema allgemein sehr interessant und bin etwas enttäuscht dass man mir dass im bakk nur so unzureichend nähergebracht hat. Objektorientierte Modellierung war damals ja noch nicht pflicht. Hat das schon wer gemacht und kann es als zb freu/wahlfach empfehlen?

    OOAE, wie dieses Fach damals noch hieß, kann ich nicht empfehlen. Vielleicht ist die LVA inzwischen besser geworden, aber ordentliche Klassenstrukturen entwerfen lernst du dort nicht.
    Empfehlenswert in der Richtung ist mMn 'Objektorientierte Programmierung' bei Prof. Puntigam, sofern du das nicht schon gemacht hast.


  • Empfehlenswert in der Richtung ist mMn 'Objektorientierte Programmierung' bei Prof. Puntigam, sofern du das nicht schon gemacht hast.

    Das hab ich schon gemacht. War auch ganz interessant, es wurden auch ein paar entwurfsmuster vorgestellt, aber wirklich objektorientiertes design hat man da auch nicht vermittelt bekommen. Ich denk advanced software enginnering wäre interessant da man die arbeitsschritte analyse und entwurf im gegensatz zu sepm selbst machen muss.

  • OOD ist (wie so vieles andere in der Informatik) etwas, was viel Erfahrung braucht und nicht wirklich vermittelt werden kann.

    [font=verdana,sans-serif]"An über-programmer is likely to be someone who stares quietly into space and then says 'Hmm. I think I've seen something like this before.'" -- John D. Cock[/font]

    opentu.net - freier, unzensierter Informationsaustausch via IRC-Channel!
    Hilfe und Support in Studienangelegenheiten, gemütliches Beisammensein, von und mit Leuten aus dem Informatik-Forum!

  • Was ich jetzt so gelesen hab ist das Brückenmuster gut geeignet für db andbindung und graphische benutzeroberflächen. Ob das jetzt für mich das ideale wäre bezweifle ich aber.

    Nein, das Bridge Pattern hat nichts mit Datenbanken oder GUIs zu tun. Das sind hoechstes Anwendungsbeispiele, um die Funktion zu beschreiben. Bridge ist ein Beispiel dafuer, wie man Vererbung durch Komposition ersetzen kann. Schau dir in diesem Zusammenhang auch Strategy an. Ob das jetzt in Deinem Fall sinnvoll ist kann man aber nicht so pauschal sagen. Das haengt von vielen Faktoren ab, z.B. wie dein Code genau aussieht und was du in Zukunft alles damit machen wirst, wer alles damit arbeiten wird usw.

    OAE hab ich gemacht und fand es eigentlich ganz gut; allerdings geht es da vor allem um UML modellierung und nicht wirklich um OOP Design. Die Vorlesung vom Puntigam kann ich empfehlen. Ich hab sie zwar anrechnen lassen, aber ich hab den zweiten Teil gemacht (fortgeschrittene OOP) und ich habe Freunden beim ersten Teil zur Seite gestanden. Puntiam macht das sehr gut.

    Ansonsten kann ich die ueblichen Buecher empfehlen, die ich eh in jedem zweiten Post empfehle: Head First Design Pattern, Code Complete, Structure and Interpretation of Computer Programs usw. Siehe http://www.informatik-forum.at/showthread.php?t=56323

    Und dann natuerlich: code lesen, code lesen, code lesen.

    PS: Eingedeutschte Bezeichnungen fuer englische Fachbegriffe sind doch das letzte. Brueckenmuster, also wirklich.

  • Beides zu verwenden, also vor die abstrakte Klasse dann noch ein Interface zu schalten, wuerde ich als unnoetig und ueberspezifiziert betrachten.

    ok, argumentation vergessen: da es sich ja um ne lib handlet, würd ich auf jeden fall ein interface verwenden, um bei späteren refactoring flexibler zu sein und um meine klassenstruktur nicht den usern der lib zu offenbaren. die könnten dann nämlich ungewollte sachen damit anstellen, sie zB erweitern oder so. das wäre bei einem framework (zb Swing) erwünscht, nicht aber bei einer lib.
    Die abstrakte Klasse deshalb, um eine hierachie in das modell zu bekommen, natürlich nur wenn man das möchte. eine flache hierachie hat auch ihre vorteile. das hängt von mehreren faktoren ab.
    auf jeden fall ein interface verwenden wenn man eine lib schreibt würd ich sagen.

    lg

    computer says nooooohhhh!

  • Stimmt. Das ein Client dann von einer abstrakten Klasse natuerlich erben duerfte, hatte ich uebersehen. In Java ergibt sich dadurch natuerlich ein Unterschied zum (Java-)Interface, den ein Benutzer mitbekommt wenn sich etwas aendert. Gutes Argument.

Jetzt mitmachen!

Sie haben noch kein Benutzerkonto auf unserer Seite? Registrieren Sie sich kostenlos und nehmen Sie an unserer Community teil!