Entwurfsmuster



  • Hallo Forum.

    Ist bastle schon seit einer Weile an einem Problem und komme nicht so recht zum Ziel. Ich möchte in C++ folgende Struktur umsetzten. Ich habe das ganze mal auf konkrete Objekte bezogen um das ganze besser zu beschreiben:

    Ich habe 1 bis 3 gleiche Instanzen einer Klasse. Die Klasse repesentiert eine verfahrbare Eineit. Ich nenne die Klasse mal CRobo. D.h. intern sind Motoren und andere Elektronische Bauteile vorhanden.

    Auf der anderen Seite gibt es wieder 1 bis 3 gleiche Instanzen einer Klasse. Diese Klasse (ich nenne sie mal CPerson) wiederum kann etwas von dem oben genannten CRobo wollen. CPerson ist wiederum weiter spezialisiert. CPersonA, CPersonB und CPersonC. Dieses "wollen" wird in einem Job (CJob) zusammen gefasst. Z.b. soll einer der 3 Robos an eine Position X,Y fahren. Wenn er das getan hat, soll er die CPerson informieren, dass er es gemacht hat + einem Result mitgeben. Z.b. Bin nun an Pos. X,Y, ok.

    Die Kommunikation soll aber nicht direkt von CPerson an CRobo gehen sondern über einen Manager (CManager - Sigleton). Dieser Manager empfängt nun von einer beliebigen CPerson den CJob (Aufgabe die der CRobo machen soll: Position, ...). Der Manager kann die Jobs intern speichern und der reihe nach abarbeiten. Der CJob wird dann an einen CRobo weitergegeben sobald dieser bereit für einen neuen Job ist. Dieser Robo meldet sich dann irgendwann zurück und der ürsprüngliche Aufrufer (CPerson) wird informiert -> läuft auch wieder über den CManager.

    CPerson, CJob und CRobo sind abgeleitete Klassen. CPerson und CRobo haben einen Ursprung in CActor. Der Manager hat nun eine interne Liste in der die Jobs und der Aufrufer/Caller (CPersonA, B, C) abgelegt werden.

    Meine Probleme hab ich nun damit an dem Manager die Jobs + Instanz des Callers zu geben. Caller als Referenz konnte ich nicht in einer Liste ablegen. Bei Pointern verlor ich die Typ-Information. D.h. der Job (Position + Caller) konnte nicht richtig an einen beliebigen Robo durchgestellt werden. Der Robo hält sich nun seinen aktuellen Job. Es war mir nicht mal möglich, Methoden Aufrufe bzw. die ganze Struktur so festzulegen, dass im ersten Ansatz der Robo direkt eine Funktion des Callers (CPersonA) aufruft und ihm das Result mitgibt.

    etwa in der Art (pseudo code):

    CRobo::ExecuteJob( CJob &oJob )
    {
       ...
       oJob.SetResult( m_fResultX, m_fResultY,... );
       ...
       oJob.GetCaller().SetJobDone( oJob );
       ...
    }
    
    ...
    
    CPersonA::DoSomething()
    {
       CJob oJob( 5.9, 6.9, 0.5, eMoveJob );
       CManager::getInstance().SetJob( oJob, this );
       ...
    }
    
    CMagager::SetJob( CJob &oJob, CActor &oActor )
    {
       m_oLobList.push_back( oJob + oActor );
       ...
    }
    

    Ich habs nicht geschaft das ganze mit Pointern oder Referenzen hinzubekommen, dass die oben genannte Stuktur funktioniert.

    Hat jemand eine Idee wie sowas umzusetzen ist?

    Viele Grüße

    motom



  • Mach dir doch ein eigenes Struct, welches die JobInfo hält:

    struct JobInfo
    {
        Actor* actor;
        Job* job;
        JobInfo( Actor* a, Job* j )
         : actor(a), job(j)
        {}
    };
    

    So ein Objekt kannst du wunderbar in einer Liste speichern:

    class JobManager
    {
        std::queue<JobInfo> m_jobs;
    public:
        addJob( Actor* a, Job* j ) {
            m_jobs.push( JobInfo(a,j) );
        }
    };
    

    So auf die Schnelle.
    Du kannst dir ja auch mal boost::signals (boost::signals2 falls threads) anschauen. Das was du willst ist ja eigentlich ein Event-System.



  • Wie sieht Actor aus, ist das ein Interface für die "done"-Aufrufe? Warum du den Umweg über den Manager gehst, erschließt sich mir auch noch nicht; oder werden die Jobs immer an den nächsten freien Robo vergeben und nicht an einen fixen?

    Ansonsten, am SetResult sollte es ja nicht hapern; für die "done"-Benachrichtigung könntest du Funktionszeiger verwenden (boost::function bzw std::tr1::function bzw std::function), ein entsprechendes Interface oder Memberfunktionszeiger. Für den Verbund aus Job und Actor kannst du ein IrgendeinContainer<pair<Job,Actor*> > nutzen oder 'ne neue struct dafür definieren.



  • Hallo und vielen Dank für die bisherigen Ideen.

    CActor ist einfach eine Basisklasse in der die Geminsamkeiten drinn sind

    Der CManager soll einfach die Zugriffe auf die Instanzen von CRobo "koordinieren". Ein direkter Zugriff von CPerson(X) auf den einzelnen CRobo soll nicht geschehen - denn in einer späterem Ausbau-, Ableitungsstufe soll der CManager noch selbstständig festlegen, welcher CJob an welchen CRobo gegeben wird, weil der eine z.B. grad etwas tut oder an die etsprechende Pos. rein pysikalisch nicht erreichen kann. Halt etwas mehr dynamik. Momentan happerts bei mir noch am Design der Schnittstellen zwischen den 3 Schichten.

    So etwas ähnliches wie mit dem struct hatte ich schon probiert. Irgendwie
    hatte ich jedoch bei den Pointern das Problem, dass wenn der CRobo die Methode von CPersonA oder CPersonB oder ... (mit Hilfe des Pointers auf die Caller Instanze) aufrufen sollte (SetJobDone -> die Rückmeldung das es gemacht wurde + Status), dass mir dann die TypeInformationen nicht vorlagen. Somit gabs die Meldung, dass SetJobDone in CActor nicht vohanden war. Die gibts erst ne Ableitungsstufe tiefer.

    Ich muss eingestehen, dass meine Kenntnisse noch nicht so umfassend sind um die Möglichkeiten die es gibt zu erkennen. Hab mir schon etwas Lektüre (Entwurfsmuster Addison Wesley) zugelegt um meinen Horizont zu erweitern, aber das lesen geht noch schleppend voran.

    Kleine Rahmenbedingung: Das Ganze muss unter MS Visual C++ 6.0 gehen. Weiss nicht obs da eventuell manchen Dinge mit der STL und der boost-lib und so weiter schon drinn sind.

    Gruß

    motom



  • Kleine Ergänzung noch. Ich würde gern ohne zusätzliche Libs wie boost usw. auskommen.

    Call by reference wird wohl bei meinem geplanten design nicht klappen? Habs jedenfalls nicht hinbekommen. Weil da hätte man ja noch die TypeInfos... um die richtige Klasse zu erkennen und dann die etsprechende Methode aufzurufen?

    CPersonA -> gibt CJob an CManager. Der Speichert es in einer Liste und
    CManager -> gibt CJob an CRobo. Dieser erledigt diesen und antwortet indem er die
    JobDone() Methode von CPersonA, CPersonB oder einer anderen aufruft.
    Sind jeweils eigene Klassen - abgeleitet von CPerson. Mir gehts eigentlich nur um diese "simple" Anfrage <-> Antworkverkettung, wo der der die Anfrage stellt nicht unbedingt auf die Antwort wartet sondern was anderen weitermachen könnte.

    Gruß

    motom



  • Ohne boost und mit MSVC 6.0. Ohje...

    Na gut, da sowohl die Robots als auch die Personen die Job-Klasse kennen, kannst du neben (oder in) dieser ein Interface deklarieren:

    struct JobDoneListener
    {
        virtual void onJobDone( /*whatever*/ ) = 0;
    };
    

    CPerson erbt davon und überschreibt die Methode entsprechend. In die Job-Klasse machst du einen Pointer auf JobDoneListener, den die CPerson-Klasse dann mit "this" belegt. Wenn der Job fertig ist, rufst du über dieses Interface die onJobDone-Methode auf und der Kuchen ist gegessen 🙂


Anmelden zum Antworten