Diamond of Death: Gibt es einen Namen oder Patterns für meinen speziellen Fall?


  • Global Moderator

    Ein Auto ist eine abstrakte Basis.
    Ein Flugzeug ist eine andere Basis (egal ob abstrakt oder nicht).
    Ein Mercedes ist ein Auto und nicht mehr abstrakt.
    Ein BMW ist ein Auto und nicht mehr abstrakt.
    Ein FlugAuto ist ein Auto und ein Flugzeug und weiterhin abstrakt.
    Ein FlugMercedes ist ein Mercedes und ein FlugAuto (und somit ein Auto und ein Flugzeug) und nicht mehr abstrakt.
    Ein FlugBMW ist ein BMW und ein FlugAuto (und somit ein Auto und ein Flugzeug) und nicht mehr abstrakt.

    Oder ohne Autobeispiel erklärt: Eine abstrakte Klasse B leitet selber von einer anderen abstrakten Klasse A ab. Die konkreten Verwirklichungen von B werden erzeugt, indem man sie von anderen konkreten Verwirklichungen von A ableiten lässt.

    Ich kann mir nicht vorstellen, dass ich der erste mit einem solchen Fall bin. Ich weiß aber nicht so recht, nach welchen Stichworten ich suchen soll, um herauszufinden, ob es da irgendwelche nützlichen Patterns oder sonstige Ratschläge gibt, wie man das vielleicht besser machen kann.

    Und Nein, ich denke nicht, dass Komposition hier passend wäre. Das Flugauto mag aus einem Auto und Flügeln bestehen, aber es ist auf jeden Fall ein Auto und kann (und soll!) überall dort eingesetzt werden, wo man ein Auto einsetzen kann. Ebenso soll der FLugBMW überall einsetzbar sein, wo ein Auto, ein Flugzeug, oder ein FlugAuto erwartet wird.



  • @seppj sagte in Diamond of Death: Gibt es einen Namen oder Patterns für meinen speziellen Fall?:

    soll der FLugBMW überall einsetzbar sein, wo ein Auto, ein Flugzeug, oder ein FlugAuto erwartet wird.

    Ok, aber Du erzwingst dass er auch überall eingesetzt werden kann wo ein (klassischer) BMW eingesetzt werden kann?
    Ist das wirklich nötig? Bzw hat BMW-sein ("is-a BMW") überhaupt irgendeine Relevanz für andere Akteure?
    Wenn nicht dann sollte FlugBMW doch lieber ein FlugAuto mit BMW-Innereien sein (Komposition), statt selbst ein BMW(-Auto).

    Namen kenn ich dafür nicht, taufen wir es hiermit FlyingMercedes pattern. 🙂



  • @seppj sagte in Diamond of Death: Gibt es einen Namen oder Patterns für meinen speziellen Fall?:

    Ich kann mir nicht vorstellen, dass ich der erste mit einem solchen Fall bin.

    Wenn Du es als schlichte Kosten/Nutzen Angelegenheit betrachtest, ist es wahrscheinlich viel einfacher direkt hier zu fragen, sobald Du konkrete Fragen zum Design hast, anstatt zu fragen, nach welchen Stichwoertern du googlen musst, um auf relativ oberflaechliche Diskussionen im Netz zu stossen, die dir keine grossartigeren Gedanken bieten als die, die Du hier innerhalb kurzer Zeit erarbeiten kannst.



  • @Columbo: du solltest deinen Beitrag noch mal nacheditieren:

    K...n/Nutzen

    LOL



  • 😆


  • Global Moderator

    @columbo sagte in Diamond of Death: Gibt es einen Namen oder Patterns für meinen speziellen Fall?:

    Wenn Du es als schlichte Kotzen/Nutzen Angelegenheit betrachtest, ist es wahrscheinlich viel einfacher direkt hier zu fragen, sobald Du konkrete Fragen zum Design hast, anstatt zu fragen, nach welchen Stichwoertern du googlen musst, um auf relativ oberflaechliche Diskussionen im Netz zu stossen, die dir keine grossartigeren Gedanken bieten als die, die Du hier innerhalb kurzer Zeit erarbeiten kannst.

    Stimmt. Es geht um verschiedene Datenleserklassen.

    1. Die ganz allgemeine Klasse für Daten ohne jede bekannte Struktur. Die hat einfach eine Methode die alles ohne weitere Interpretation liest.

    2. Eine spezielle Klasse für Daten, die irgendwie eine Art 'Schlüssel' haben, den man abfragen kann. Deren Lesemethode kann eingeschränkt werden auf eine vom Benutzer anzugebende Menge von speziellen Schlüsseln.

    3. Eine spezielle Klassen für Daten, die irgendwie ein Konzept einer Ordnung nach irgendeinem Wert haben. Diese haben eine Lesemethode, die man darauf einschränken kann, nur Daten 'zwischen' zwei Werten, oder 'vor', oder 'nach' einem Wert zu lesen. Sprich: Ob diese Daten einen Wert haben, der in einem gewissen Intervall liegt.
      Jetzt wird's aber trickreich, denn das ist erst einmal nur eine abstrakte Beschreibung einer Schnittstelle für ein solches Konzept. Davon gibt es zwei verschiedene konkrete Ausführungen:

      1. Einmal können die Daten so organisiert sein, dass jeder Datensatz einen Punkt auf einer Art 'Zeitstrahl' darstellt. Ein einzelner Datensatz kann beispielsweise für exakt den 24. Oktober 13:45:17 sein.
      2. Oder aber ein Datensatz kann selber eine Art Intervall auf solch einem Zeitstrahl darstellen. Ein Datensatz kann beispielsweise für 1. Oktober bis 1. November sein.

      Beides implementiert das gleiche Konzept, dass man diese Daten filtern kann, ob sie in einem Intervall liegen. Daher das gleiche Interface. Die interne Umsetzungslogik ist jedoch vollkommen anders, will heißen, die Implementierung der virtuellen Methoden ist jeweils ganz anders.

    4. Nun gibt's natürlich auch Datensätze mit beidem, einem Schlüsselkonzept und einem Intervallkonzept. Die haben eine Lesefunktion mit der Möglichkeit zur Angabe von gewünschten Schlüsselwerten, und zur Einschränkung der gelesenen Daten auf ein bestimmtes Intervall.
      Das ist aber auch erst einmal nur eine ganz abstrakte Sache, denn diesem Datenleser ist es vollkommen egal, ob das nun Daten nach Konzept 3.1 oder Konzept 3.2 sind, Hauptsache sie implementieren irgendwie die Lesefunktion, die die von-bis-Logik versteht.
      Dementsprechend gibt es aber letztlich zwei konkrete Umsetzungen des abstrakten Konzepts 4, nämlich einmal mit Daten nach Konzept 3.1 und einmal nach 3.2.

    Konkret umgesetzt habe ich das nun damit, dass es eine abstrakte Klasse 4 gibt, die von 2 und 3 erbt, und dann konkrete Klassen 4.1 und 4.2, die jeweils sowohl von Klasse 4, als auch von 3.1 beziehungsweise 3.2 erben. Und 2 und 3 erben jeweils von 1, aber das ist eigentlich nicht wichtig.

    Der Grund dafür ist halt, dass es nun diverse Funktionen geben kann, die die Leser bedienen. Manche der Funktionen benötigen ein Objekt eines Lesers, der die Daten nach Schlüsseln filtern kann. Andere nach Intervallen. Manche brauchen beide Möglichkeiten, anderen reicht auch die ganz uneingeschränkte Lesefunktion. Und ich will diese Funktionen natürlich mit passenden Leseobjekten füttern können, je nachdem, was diese können. Was durch dieses Vererbungsmonster ausgedrückt wird.

    Das ist ein Design, mit dem ich durchaus leben kann, aber mir drängt sich der Gedanke auf, dass das ein überdesigntes Monstrum ist und ich gerade etwas erfunden habe, dass es viel einfacher gibt. Oder wo es irgendwelche Tricks gibt, mit denen das ganze schöner wird. Insbesondere stört mich so ein bisschen, dass die Klassen 4.1 und 4.2 gar keinen Code haben, sondern sich allein durch ihre Vererbungsbeziehung definieren. Die Umsetzung ihrer Logik erfolgt in den abstrakten Methoden der Klasse 4 und in den konkreten Methoden in den Klassen 3.1 bzw. 3.2; die Klassen 4.1 und 4.2 führen bloß diese beiden Komponenten zusammen. Das riecht das Komposition, ist es aber aus obigen Gründen nicht.

    Mir ist durchaus schon der Gedanke gekommen, dass dies eine Art Query Generator für Arme ist, und die "richtige" Lösung wäre, eine Art von Query Language anzubieten, ganz unabhängig von den Daten. Dann entfiele die ganze Klassen- und Vererbungslogik. Es ginge in diesem Fall jedoch am Ziel vorbei, wenn man eine weitere Sprache lernen müsste, denn es geht durchaus auch darum, ein einfaches, verständliches Interface zum Datenlesen zu haben.



  • Also

      +---> 2 +-----------------+
    1 |                         v
      +---> 3 +---------------> 4 +-------+
            +                       |     |
            |                       v     |
            +-------> 3.1 +------> 4.1    |
            |                             v
            +-------> 3.2 +------------> 4.2
    

    Ich hab gerade nicht die Zeit, mich mehr als fluechtig damit zu beschaeftigen, aber koenntest Du die Implementierung von 3 nicht via pimpl auslagern, und in einer (einzigen) Konkretisierung von 4 instanziieren? Somit bleibt die Eigenschaft, Ordnung nach einem Wert zu haben, bestehen, aber die Hierarchie vereinfacht sich. Sicher hast Du das aber schon bedacht.

    Edit: Ich mir eben gerade nicht sicher, ob die Instanzen von 4.* die konkreten Implementierungen von 3.* auch offenlegen muessen, weil das teil der Logik ist? I.e. ist es notwendigerweise so, dass zwei Konkretisierungen von 4 existieren muessen, weil es zwei separate Typen geben muss, die zwei separate Funktionen bereitstellen?


  • Global Moderator

    Ja, eine pimpl-artige Variante wäre eine Lösung. Ich hatte das bisher nicht ernsthaft in Erwägung gezogen, weil ich unnötige Komplexität bei der Objekterzeugung vermeiden wollte. Aber du hast mich dazu gebracht, noch einmal genauer darüber nachzudenken. Das Klassen-Wirrwarr ist auch schon unnötige Komplexität. Das Ding braucht also sowieso eine gute Factory. Und dann ist es auch kein Problem mehr, bei der Erzeugung verschiedene Implementierungen zusammen zu führen, das macht dann ja die Factory automatisch. Ich denke, so mache ich das.