Projektaufteilung in Classes



  • Guten Morgen.

    Ich bin gerade dabei mein erstes mittelgroßes Projekt zu planen.
    Leider habe ich das Konzept von OO noch nicht ganz verstanden - so scheint es nämlich. Müsst ich sonst diese Frage hier stellen?

    Vielleicht könnt ihr mir helfen, zu sagen in welche Klassen ich das Projekt aufteilen sollte?

    Es geht um folgendes:

    Nachdem man mein Programm aufgerufen hat, erscheint ein Login-Formular.
    Der User kann ein Haken setzen, damit die Logindaten gemerkt werden.
    Nun hat er ein Menü vor sich, welches die Punkte
    "New", "inbox", "settings", ... beinhaltet.
    Klickt er auf New, kann er eine Handynummer und eine SMS eintippen.
    Wenn er sie absendet:
    a) prüft der Rechner, ob er mit dem Internet verbunden ist
    b) versucht er sie über ein Onlinedienst zu versenden
    c) ansonsten sendet er sie per GSM Moden.

    Ich stehe gerade am Anfang, habe gerade mal die Funktionen
    haveInternet(), sendGSM(), postHTTP(). Der rest ist direkt in der main() Methode implementiert.

    Trotzdem ist das "gerade-mal" 200Zeilen Projekt einfach nur absolut unübersichtlich.
    Könnt ihr mir da unter die Arme greifen?



  • Vielleicht solltest du erstmal mit etwas deutlich kleinerem anfangen, wenn du noch an Grundlagen wie Aufteilung in Klassen und Klassendesign arbeitest.



  • @pumuckl: Ich habe mich selbst gewundert. Normalerweiße fällt mir sowas nicht schwer - ganz im Gegensatz bei diesem Projekt.

    Ansich würde ich daraus jetzt erst eine Klasse machen, welche sich um den versand kümmert. Sollte man das nicht aber eher in noch 2 kleinere aufteilen?
    Statt nur class sms_send lieber via_http & via_gsm.

    Mein Problem ist einfach, dass ich nicht weiß, wie "tief" ich trennen soll.
    Theoretisch könnte man ja sogar jede methode in eine eigene classe packen (was aber zumindest hier, quatsch wäre).



  • Wie wärs mit:

    class SmsSender
    {
    public:
       virtual ~SmsSender(){}
       virtual bool CanSend() const = 0;
       virtual void Send(const SMS& sms) = 0;
    };
    
    class HttpSmsSender : public SmsSender
    {
    public:
       virtual bool CanSend() const override;
       virtual void Send(const SMS& sms) override;
    };
    
    class GsmSmsSender : public SmsSender
    {
    public:
       virtual bool CanSend() const override;
       virtual void Send(const SMS& sms) override;
    };
    
    class TwoWaySmsSender : public SmsSender
    {
    public:
       virtual bool CanSend() const override
       {
          return httpSender_.CanSend() || gsmSender_.CanSend();
       }
       virtual void Send(const SMS& sms) override
       {
          if(httpSender_.CanSend())
          {
              httpSender_.Send(sms);
          }
          else if(gsmSender_.CanSend())
          {
              gsmSender_.Send(sms);
          }
          else
          {
              throw std::runtime_error("Failed to send sms");
          }
       }
    private:
       HttpSmsSender httpSender_;
       GsmSmsSender gsmSender_;
    };
    

    ?



  • Schau Dir eifach erst nochmal die wichtigsten Grundprinzipien der OOP an (SOLID). Mit am wichtigsten ist oft das Single Responsibility Principle. Jede Klasse, jede Methode hat genau eine Zuständigkeit. Damit kannst du ausgehend von einem zunächst monolithischen Design deine Klassen in immer kleinere, sinnvollere Happen zerteilen. Zum Beispiel, wirst Du sicher eine Klasse für eine Nachricht haben. Diese hat die Eigenschaften Empfänger und Inhalt. Die einzige Verantwortlichkeit der Klasse ist es die Gültigkeit einer Nachricht sicherzustellen, z.B. das der Inhalt einer SMS immer < xx Zeichen sein muss (das nennt man Invarianten). Dann wirst Du eine weitere Klasse haben, die sich um den Versand dieser Nachricht kümmert. Bzw. wirst Du wahrscheinlich eine Familie von solchen Klassen haben, eine für jede Versandart. Oder aber es ist nur eine Versenderklasse die unterschiedliche Protokolle, die wiederum Klassen sind verwendet. Was das optimale Design ist, stellt sich i.d.R. erst während der Implementierung heraus.



  • Claaas schrieb:

    Leider habe ich das Konzept von OO noch nicht ganz verstanden - so scheint es nämlich. Müsst ich sonst diese Frage hier stellen?

    Vielleicht könnt ihr mir helfen, zu sagen in welche Klassen ich das Projekt aufteilen sollte?

    Beginne mit der Erweiterung deines Verständnisses ganz unten:
    --> ohne OOP: Es gibt nur Strukturen, keine Klassen
    --> mit OOP: Aus Strukturen kann man Klassen mit eigener Funktionalität machen

    Auch für Strukturen muss man sich einen sinnvollen Aufbau überlegen. Für Klassen kommt dann noch der Entwurf der Funktionalität hinzu und was man mit Klassen noch alles machen kann. Das alles zuerst mit sehr einfachen Anforderungen probieren. Wäre 'C mit Klassen'. Zum Verständnis gut, hier nur oft verpönt.

    Ansonsten bleibt das Design eines Programmes immer die Hauptaufgabe jeder Programmentwicklung und die musst du selbst leisten.



  • Dein Projekt ruft nicht "Bitte bau mich objektorientiert". Also laß es und erzwinge keine Klassen, wo sich nicht hingehören.



  • volkard schrieb:

    Dein Projekt ruft nicht "Bitte bau mich objektorientiert". Also laß es und erzwinge keine Klassen, wo sich nicht hingehören.

    Welches Projekt schreit denn wirklich nach OOP?



  • knivil schrieb:

    volkard schrieb:

    Dein Projekt ruft nicht "Bitte bau mich objektorientiert". Also laß es und erzwinge keine Klassen, wo sich nicht hingehören.

    Welches Projekt schreit denn wirklich nach OOP?

    Allem voran Simulationen (kein Zufall, daß diese frühe OO-Sprache Simula hieß), und auch Armeenschiebespiele wie "Age of Empires" oder FPS wie "Counter Strike".



  • Gibt es einen Compiler, der rufen kann "Das Design ist nicht optimal und dieses Design dann verbessert?" 😕 Könnte man gebrauchen! 😉



  • berniebutt schrieb:

    Gibt es einen Compiler, der rufen kann "Das Design ist nicht optimal und dieses Design dann verbessert?" 😕 Könnte man gebrauchen! 😉

    Das kann jeder SPL-Compiler. (Schlechter Informatikerwitz, SPL steht für Suche-Problem-und-Löse.)

    Außerdem sprach ich nicht von einem Compiler, sondern von einem Projekt, das ruft. Das ist so ein Unterschied wie zwischen objektorientierter Programmierung und objektorientierter Programmiersprache.



  • Also meint ihr, ich brauche da keine weitere Klassen um das ganze übersichtlicher zu gestalten?



  • claaas schrieb:

    Also meint ihr, ich brauche da keine weitere Klassen um das ganze übersichtlicher zu gestalten?

    Willst du das Projekt so lassen wie es ist und nie erweitern und den Code nur noch rumgammeln lassen, dann brauchst du keine Klasse.
    Willst du lernen, wie man größere Projekte enwickelt oder dieses Projekt noch weiter machen, kann man ne ganze Menge Klassen machen.



  • claaas schrieb:

    Also meint ihr, ich brauche da keine weitere Klassen um das ganze übersichtlicher zu gestalten?

    Naja, bei haveInternet(), sendGSM(), postHTTP() frage ich mich, WER tuts?
    haveInternet(), wer hats Internet? Soll ich eine Klasse dafür bauen? Es wäre notwendig, wenn es mehrere Internethaber geben könnte und die auch verschiedene Internets haben könnten. Oder wenn es mehrere zusammenhehörende Variablen (handles) wären.

    sendGSM(), wer sendet? Bringt's eine Erleichterung, eine Klasse GsmSender zu basteln, sind für das Sendenkönnen (mehrere) Variablen nötig außer der Zieltelefonnummer und dem SMS-Text? Kann der GsmSender so gemacht werden, daß man ihn glerichermaßen sowohl in einer Konsoleanwendung als auch in einer grafischen Anwendung benutzen kann? Wenn ja, stehen die Zeichen recht gut für so eine Klasse.

    Aber viel wichtiger ist, daß Du nicht 200 Zeilen in eine Funktion packst! Die meisten meiner Funktionen haben 6 oder weniger Zeilen (GUI-COde nicht gewertet, der ist immer groß).



  • Claaas schrieb:

    Nachdem man mein Programm aufgerufen hat, erscheint ein Login-Formular.
    Der User kann ein Haken setzen, damit die Logindaten gemerkt werden.
    Nun hat er ein Menü vor sich, welches die Punkte
    "New", "inbox", "settings", ... beinhaltet.
    Klickt er auf New, kann er eine Handynummer und eine SMS eintippen.
    Wenn er sie absendet:
    a) prüft der Rechner, ob er mit dem Internet verbunden ist
    b) versucht er sie über ein Onlinedienst zu versenden
    c) ansonsten sendet er sie per GSM Moden.

    Ich stehe gerade am Anfang, habe gerade mal die Funktionen
    haveInternet(), sendGSM(), postHTTP(). Der rest ist direkt in der main() Methode implementiert.

    Wie hast du dein "Login-Formular" in main bekommen? Was ist das für ein GUI Framework?



  • volkard schrieb:

    berniebutt schrieb:

    Gibt es einen Compiler, der rufen kann "Das Design ist nicht optimal und dieses Design dann verbessert?" 😕 Könnte man gebrauchen! 😉

    Das kann jeder SPL-Compiler. (Schlechter Informatikerwitz, SPL steht für Suche-Problem-und-Löse.)
    Außerdem sprach ich nicht von einem Compiler, sondern von einem Projekt, das ruft. Das ist so ein Unterschied wie zwischen objektorientierter Programmierung und objektorientierter Programmiersprache.

    Dann wird also auf Projektebene ein SPL = "Suche Personal Trainer - zur Programmierung - für Lau" gesucht? 😕 Gibt es hier doch im Forum. Im Moment höre ich das Projekt nicht rufen, allenfalls den Fragesteller! Ich klinke mich dann mal aus mangels Ernsthaftigkeit zum Thema. daddeldu! :p Ich kenne auch noch so einen Witz: "Da stehen sich Hardware und Software fassunglos gegenüber!"



  • Danke volkard. So werde ich es auch machen.


Log in to reply