richtiges Design?



  • Hi,

    ich muss unterschiedliche Daten verarbeiten und verwende zur Datenhaltung eine eigene Klasse.
    Die Ausgabe hab ich ebenfalls in eine eigene Klasse gesteckt, dass ich Drucker, Monitor, Datei, usw. getrennt behandeln kann (soll unterschiedlich sein).
    Ich protokolliere wie die Daten durch mein Programm "geschleust" werden. Dafür verwende ich eine weitere Klasse.

    sieht prinzipiell so aus:

    class Data  
    {
    public:
        std::vector<CString> messages;
        Data();
        virtual ~Data();
    
    };
    
    class MsgHandler  
    {
    public:
        Data *pData;
        MsgHandler(Data *pGlobalData);
        virtual ~MsgHandler();
        void OutputMsg(bool bfileout, CString Filename);
    };
    
    MsgHandler::MsgHandler(Data *pGlobalData)
    {
        pData = pGlobalData;
    }
    
    void MsgHandler::OutputMsg(bool bfileout, CString Filename)
    {
        CString Dummy;
    
        if (bfileout){
            FileHandler fh;
            for (int i=0; i<pData->messages.size(); i++){
                Dummy = pData->messages[i];
                fh.WriteToFile(Filename, Dummy);
            }
        }
        else{
            for (int i=0; i<pData->messages.size(); i++){
                Dummy = pData->messages[i];
                std::cout << static_cast<const char *>(Dummy) << std::endl;
            }
        }
    }
    
    class TestSuiteFunctions  
    {
    public:
        Data *pData;
        TestSuiteFunctions(Data *pGlobalData);
        virtual ~TestSuiteFunctions();
        void writeMsg(CString Msg);
    };
    
    TestSuiteFunctions::TestSuiteFunctions(Data *pGlobalData)
    {
        pData = pGlobalData;
    }
    
    void TestSuiteFunctions::writeMsg(CString Msg)
    {
        pData->messages.push_back(Msg);
    }
    
    int main()
    {
    Data *pGlobalData = new Data;
    TestSuiteFunctions *pTSF = new TestSuiteFunctions(pGlobalData);
    MsgHandler *pMsgH = new MsgHandler(pGlobalData);
    
    pTSF->writeMsg("This is a test!!");
    pTSF->writeMsg("and another ...");
    pTSF->writeMsg("and another ...");
    pTSF->writeMsg("and the last.");
    pMsgH->OutputMsg(true,"e:\\temp\\temp.txt"); 
    
    delete pGC;
    delete pMsgH;
    delete pTSF;
    delete pGlobalData;
    }
    

    Das funktioniert auch soweit. Doch ich denke das ist nicht die richtige Vorgehensweise. Ist es z.B. richtig im Konstruktor der TestSuiteFunktion Klasse einen Zeiger auf die Data Klasse zu übergeben? oder soll ich das in der Funktion "writeMsg" als Parameter machen??
    Oder gibt es da sowas wie z.B. die GetDocument Funktion bei der MFC ??

    Ich hoffe ihr schnallt was ich meine 🙄 🙂

    Legolas



  • Tun wir, tun wir.

    Um es kurz zu machen: Du erstaunst mich. Weil Du auf der einen Seite so schöne Dinge tust wie std::vector verwenden, virtuelle Destruktoren, eine Trennung zwischen Daten und View einführst, TestSuite-Klassen hast, aber Deine Variablen in der Klasse sind public, und Du verwendest überhaupt keine const oder Referenzen, auch erscheint mir die Art der Instanziierung der Objekte im Beispiel komisch: warum machst Du das mit new auf dem Heap, statt die Objekte direkt auf dem Stack anzulegen?

    Falls das wg. des Beispiels nur verkürzt war und daher kommt, so verzeih meine Einwände.

    Übrigens ist der Cast von CString auf const char* potentiell gefährlich, Du solltest lieber den Cast-Operator (LPCTSTR) der Klasse selbst verwenden.

    Ich würde mir bzgl. der Testsuite-Klasse gar nicht so viel Gedanken machen, im Grundsatz ist die Idee schon richtig, da die Test-Klasse ein (festes) Objekt von data benötigt, dieses im Konstruktor zu übergeben und dauerhaft dort zu halten. Es würde sicherlich weniger Sinn machen, das als Parameter zu übergeben - dann könnte man verschiedene Objekte an das gleiche Testobjekt übergeben - ob das Sinn macht?

    Nur empfehle ich für sowas eine Referenz auf das Objekt: denn Du mußt ein Objekt haben - ein NULL-Zeiger bringt gar nix. Also empfiehlt sich eine Referenz, weil dann die Existenz des Objekts gleich gesichert ist. So mußt Du dann im Konstruktor eigentlich eine Exception werfen, wenn jemand ein NULL übergibt.

    Zur Frage nach dem GetDocument - auch wenn mich jetzt bestimmt wieder gleich jemand wg. Eigenwerbung steinigt - schlage ich mal die Lektüre von http://www.c-plusplus.net/titelanzeige.php?ISBN=3826629841 vor. Dort steht einiges über das Zusammenspiel solcher Daten- und View-Klassen.

    Die Idee an sich ist richtig, aber kommt mir hier noch etwas hakelig vor.



  • Übrigens ist der Cast von CString auf const char* potentiell gefährlich, Du solltest lieber den Cast-Operator (LPCTSTR) der Klasse selbst verwenden.

    Warum ist das gefährlich? Bei einem Cast wird doch dieser Operator automatisch aufgerufen. Er ist nur unnütz.



  • Hi,

    erst mal gracias, das Prog sieht eigentlich ein wenig anders aus. Ich habe nur ein paar Teile herausgenommen und eine main dazu gepackt.

    Aber Du hast schon recht ich hab noch das ein oder andere Defizit 🙄
    Dafür git es ja euch 🙂

    Okee, dann mach ich mich gleich mal ans Werk ...

    Legolas


Anmelden zum Antworten