Klassendesign - Wie würdet ihr das lösen?



  • Optimizer schrieb:

    Sowas nenne ich eine Komposition.

    Ich weiß, ist auch unter Containment und Embedding bekannt.



  • Optimzier:

    Das C soll dich jetzt mal nicht stören, ok? 😋

    Hast du meinen Text gelesen? Wie stellst du dir das denn vor, mit den Gettern in der Basisklasse? Meine SnapTies und Anchors haben ja noch nichtmal eine Basisklasse ...

    Was soll ich den anders beschreiben? (alles? nur nen bestimmten Part?)



  • Beim Bewegen eines Rect-Objekts brauch ich seine Anker um zu schauen, ob einer davon in der Nähe eines Snaps ist.

    Du könntest die Connectors bei dem Rect sich anmelden lassen. Sehe ich das richtig, dass man den Connector selber nicht verschieben kann, sondern nur über die Objekte, an die sie connected sind?

    also irgendwie so:

    class Rect    // davon dann abgeleitet Text usw.
    {
    public:
        ...
        void connectTo(ConnectorEndpoint*);
        void disconnectForm(ConnectorEndpoint*);
    
    private:
        ...
        std::list<ConnectorEndpoint*> connectedEndpoints;
    };
    
    class Connector
    {
    public:
        connectHead(Rect*);
        connectTail(Rect*);
    
    private:
        ConnectorEndpoint head;
        ConnectorEndpoint tail;
    };
    

    ConnectorEndpoint braucht dann auch Methoden um einen Zeiger auf seinen Connector zu kriegen, in dem es enthalten ist. Dann kann rect in der Liste der bei ihm angeschlossenen Endpoints den Endpoint fragen, von welchem Connector es ist.

    Dann könnte das evtl. so ablaufen, um einen Connector zwischen zwei Rects zu setzen:
    connectHead(rect1) ruft auf rect1->connectTo(head) und sagt dem head natürlich auch noch, an wem es connected ist.

    Erinnert mich jetzt irgendwie gerade an ne double-linked-list. 🤡
    Mir ist aber wie gesagt die ganze Problemstellung nicht so klar, deshalb hab ich wahrscheinlich Müll erzählt.



  • Sind Anchors und Snapties nicht identisch ?



  • Nein, das siehst du nciht richtig. Connectoren kann man auch selbst bewegen (daher die Ableitung von CBaseOb) ...
    ich zeig euch mal die Klassen, wie ich sie momentan hab (und nicht so lassen will! 🤡 )

    class CBaseOb
    {
    };
    
    class CRectBaseOb : public CBaseOb
    {
        CAnchors m_Anchors;
    };
    
    class CAnchors
    {
        CBaseOb* pParent;
        std::vector<CAnchor> vecAnchors;
    };
    
    class CAnchor
    {
        std::vector<CSnapTie*> vecConnectedSnaps;
    };
    
    class CSnapTie
    {
        CBaseOb* pParent;
        CAnchor* pConnectedTo;
    };
    
    class CConnectorOb : public CBaseOb
    {
        CSnapTie SnapTies[2]; //Head & Tail
    };
    

    Seht ihr die viele Abhängigkeiten?



  • Vielleicht kannst du hier was abgucken:

    http://www.codeproject.com/miscctrl/umleditor.asp



  • devil:
    Nein, bisher mal nicht. Aber wenn ich so nachdenke, könnte man ihnen vielleicht zumindest eine gemeinsame basisklasse geben.
    Momentan sehen die Klassen so aus:

    class CAnchor
    {
    public:
    
        bool IsConnected();
    
    private:
    //    int nID;
        std::vector<CSnapTie*> m_vecpConnectedSnaps;
    public:
        CSize Area;
        COLORREF Color;
        CPoint ptOffset;
        Helper::Position Pos;
        CSize Size;
        COLORREF HighlightColor;
        CSize HighlightSize;
    };
    
    class CSnapTie
    {
    private:
        CBaseOb* pOb;
        CAnchor      *pConnectedTo;
        Helper::Type SnapType;
    };
    
    class Helper
    {
    public:
        enum Position {TopLeft, TopRight, BottomLeft, BottomRight, TopMiddle, LeftMiddle, RightMiddle, BottomMiddle, Middle};
        enum Type{Head=0, Tail=1};
    };
    

    Aber man könnte es ja auch folgendermaßen machen:

    class CAnchor
    {
        Helper::Type;
        std::vector<CBaseAnchor*> ConnectedTo;
    };
    
    class Helper
    {
    public:
        enum Position {TopLeft, TopRight, BottomLeft, BottomRight, TopMiddle, LeftMiddle, RightMiddle, BottomMiddle, Middle};
        enum Type{Anchor=0, SnapHead, SnapTail};
    };
    

    Und dann einfach nur Anchors, welche nicht vom selben Typ sind, miteinander verbinden lassen.



  • @sehr schlechter tipp:
    Danke, so schlecht war der Tipp garnicht 😉 Die scheinen das ganz anders zu machen, ganz ohne Zeiger. Da wird nur ein String übergeben mit nem Namen. Hab's noch net gnaz zu Ende analysiert, aber bin mal gespannt, wie die das lösen.



  • Hm, naja ok 😉
    Der Tipp hilft mir doch nicht weiter, da bei diesem UML-Editor die Connectoren nicht frei in der Landschaft vorkommen können.



  • Hem, dein Problem hab ich nicht so ganz verstanden. Auf Arbeit bin ich übrigens auch dabei, ein Grafiktool mit Vektorgrafik-Elementen zu entwickeln. Ich habe das ganze so gelöst:

    AbstractSKD
         /\
         ||   
    AbstractShape
    

    SKD heißt das System, an dem ich arbeite, nicht verwirren lassen. Jedenfalls habe ich alle meine Grafikobjekte (Kreise, Rechtecke, Pfeile, Bemerkungstexte usw.), die die Benutzer auch frei verschieben, kopieren usw. können, von AbstractShape abgeleitet. Wenn ich jetzt, wie du, auch Verbindungslinien bräuchte, würde ich diese (also die Verbindungsline selbst) ebenfalls von AbstractShape ableiten.

    Damit aber eine Connection zwischen zwei Shapes existieren kann, kannst du ja eine Membervariable vom Typ AbstractShape hinzufügen.

    class Circle : public AbstractShape
    {
      private:
         AbstractShape* connected;
    };
    

    Machste noch setter und getter mit rein. Das müsste doch reichen?

    Wenn aber ein solches Objekt mehrere Ankerpunkte haben kann, machste einfach einen std::vector<AbstractShape*> rein. Oder bei dem Verbindungslinien-Objekt, einen leftConnected und einen rightConnected.

    Mit einer gemeinsamen Basisklasse kannste alles erschlagen. Ich habe z.B. auch die Abteilungen und die Benutzer selbst von AbstractSKD abgeleitet, so das ich auch mehrere Grafikfolien realisieren kann, und die Benutzer Parallel an einer Zeichnung arbeiten können.


Anmelden zum Antworten