Allgemeine Frage über Ersatz mehrerer und identischer If-Abfragen



  • Hallo an alle Programmierer 🙂

    Sorry, ich wusste nicht so ganz, wie ich den Titel anders schreiben konnte 😕

    Ich hätte eine ganz allgemeine Frage bezüglich einer Vorgehensweise. Erstmal zum Background: Da dies ein Arbeitsprogramm ist, kann ich keinen Quellcode veröffentlichen. Es geht allgemein um einen Excel-Importer. Dieser liest die Excel-Datei aus und überprüft, ob die Daten valide sind. Wenn er nun einen Fehler findet, gibt es zwei Möglichkeiten, je nachdem, wie es der Benutzer wünscht (er kann das Verhalten einstellen): Entweder der Import bricht beim ersten Fehler sofort komplett ab oder aber er überspringt diesen "Datensatz" einfach und geht zum nächsten (eine While-Schleife wird benutzt). Nun ist es momentan so, dass immer eine Abfrage à la "Wenn diese Daten ungleich Das sind, dann => Wenn User möchte nach Fehler beenden, beende, ansonsten fahre mit nächsten Datensatz fort". Das funktioniert natürlich, ist aber natürlich wenig wartungsfreundlich. Eine Funktion würde in so fern schwierig sein, als das es die Schleife nicht überspringen könnte (oder?). Das Programm ist zwar in Visual Basic geschrieben, dennoch interessiert mich eine Lösung auch in C++.
    So, meine Frage dazu lautet: Gibt es eine elegantere, wartungsfreundlichere Lösung des Problems?

    Vielen Dank für alle hilfreichen Antworten im Voraus 🙂



  • Musste Dich mal mit der Bool´schen Algebra vertraut machen. Da gibts gewisse Regeln der Vereinfachung.

    Konkret kann man Dir ohne Bsp.-Formeln bzw. Quellcode nicht weiterhelfen.
    Keiner verlangt ja, dass Du Deinen Quellcode aus Eurem Unternehmens-Portfolio präsentieren sollst. Aber Du kannst Dir ähnliche Bsp.-Konzepte überlegen und dass ganze noch in eine allgemeine, Programmiersprachenübergreifende Form bringen (Struktogramm, PAP).

    Grüße

    Schlitzauge 🙂



  • dsTny schrieb:

    "Wenn diese Daten ungleich Das sind, dann => Wenn User möchte nach Fehler beenden, beende, ansonsten fahre mit nächsten Datensatz fort".

    for(;;)
    {
    data = Read();
    if (InValid(data))
    {
     if (BreakOnInvalid())
        break;
     else
        continue;
    }
    Store(data);
    

    Was muss man da jetzt warten?



  • Der Name des Titels ist doch schon Programm.
    Ihm geht es nicht darum, dass etwas nicht geht, sondern dass sein Algorithmus für ihn zu sehr aufgebläht ist.

    Er möchte gerne sein Algorithmus bool´sch logischer und vor allem einfacher gestalten.
    Ansonsten versteh ich ihn falsch.



  • // true - everything is fine
    bool loadDataSet(void);
    // true - exit the loop on error
    bool stopOnError(void);
    
    // ...
    
    while (loadDataSet() || !stopOnError()) { /* everything important could be done in laodDataSet */ }
    

    Das wäre, denke ich, eine hübsche Lösung.
    Über die Wartbarkeit lässt sich zwar streiten, aber zumindest
    gibt es keine unnötigen if's 🙂



  • Schlitzauge schrieb:

    Der Name des Titels ist doch schon Programm.
    Ihm geht es nicht darum, dass etwas nicht geht, sondern dass sein Algorithmus für ihn zu sehr aufgebläht ist.

    Er möchte gerne sein Algorithmus bool´sch logischer und vor allem einfacher gestalten.
    Ansonsten versteh ich ihn falsch.

    Er fragt wie er einen Ausdruck mit 2 Ifs wartbarer schreiben kann. Und meine Frage war was man denn da warten muss. Wenn er erklärt hätte, dass sich die Anzahl und Ausprägung der Bedingungen während der Lebzeit des Programms oft ändern, würde ich das Problem erkennen aber so..



  • dsTny schrieb:

    So, meine Frage dazu lautet: Gibt es eine elegantere, wartungsfreudige Lösung des Problems?

    Schreib's in Assembler, das ist die wartungsfreudigste Lösung. Ach so, du meintest wartungsfreundlich. <scnr>



  • Wenns drum geht, dass die gleiche Abfrage mehrfach vorkommt, du aber bei Änderungen nicht jede entsprechende Codestelle warten müssen willst, dann gilt so oder so das DRY-Prinzip - Kapsel es in eine Funktion, der du die nötigen Parameter mitgibst. Das geht in C++03 in 99% der Fälle, in C++0x in 99,99% (kann mir nichts denken was das verhindern sollte).



  • Hallo,

    erstmal danke für die zahlreichen Antworten 🙂

    Ich erkläre nochmal eben das Problem mit Hilfe eines Struktogrammes (siehe diesen *link*). Man kann sich nun vorstellen, dass es viele Daten gibt, die überprüft werden müssen (verschiedene Daten, sequentiell). Immer nach demselben Muster. Man kann sich also hoffentlich vorstellen, dass, sollte z.B. noch eine Option dazukommen, man viele Zeilen Code ändern müsste, da die Abfrage "Wenn Benutzer will abbrechen bei Fehler" (gutes Deutsch :D) immer kommt, sobald irgendwelche gerade eingelesene Daten nicht valide sind.
    Ich würde einfach nur gerne wissen, ob es eine irgendeine Methode gibt, um diese Wiederkehrende If-Abfrage nur ein Mal zu schreiben, und sie dann wann immer nötig aufzurufen. Somit müsste ich nur eine Stelle im Code pflegen, sollte sich irgendetwas ändern von der Vorgehensweise.
    Eine Funktion zu definieren klappt nicht, da ich in einem Fall das Auslesen der Excel-Datei abbrechen müsste (das klappt mit einer Funktion) oder aber lediglich den momentanen Durchlauf der While-Schleife abbrechen müsste (und eben das geht mit einer Funktion nicht, oder?).

    Ich beantworte nun mal ein paar Fragen:
    @Schlitzauge: Ich habe versucht, dass nochmal mit einem Struktogramm etwas klarer zu machen. Ich hoffe, mein "Problem" ist nun verständlich 🙂
    Es ist schon richtig, dass ich den Code damit etwas entschlacken will, aber vor allem auch die Wartung/mögliche Veränderungen vereinfachen will. Da diese If-Abfrage, ob der Benutzer nun komplett abbrechen will oder eben nur diesen Durchlauf gefühlte 100x in einer Funktion (!) vorkommt (alles vom Vorgänger geschrieben), müsste ich bei einer Veränderung dieser Abfrage jede Stelle im Code ausfindig machen und extra verbessern. Eben das will ich aber vermeiden.

    @brotbernd: Du hast mich falsch verstanden 🙂 Meine Frage war nicht, wie ich diesen Algorithmus schreiben kann, sondern wie ich die If-Abfrage ("if (BreakOnInvalid())" mitsamt else-Zweig) "vereinheitlichen" kann, sodass das nur ein Mal im Code steht und ich dann die Art Funktion immer nur aufrufe.

    @DrakoXP: Sowas ist etwas schwierig, da man es sich so vorstellen muss, dass eine Excel-Zeile Daten für ein ganzes Objekt repräsentiert. Wenn auch nur eine Zelle einen invaliden Wert enthält, muss das Auslesen / der Durchgang abgebrochen werden.

    @Bashar: Da ich davor schon einmal "wartungsfreundlich" geschrieben habe, verzeihst du mir hoffentlich, dass ich es anschließend falsch geschrieben habe 😉

    @pumuckl: Gut getroffen! Aber wie mache ich es dann, dass er in der "Haupt"-Funktion, wenn der User es so wünscht, den momentanen Durchgang abbricht und nicht das gesamte Auslesen?

    So, ich hoffe, dass es etwas verständlicher ist 😉

    Nochmals danke für alle bisherigen und nachfolgenden Antworten 🙂



  • Du könntest bei einem Lesefehler eine Exception werfen. Die kannst du dann behandeln wo du willst, auch außerhalb der Funktion, die sie wirft.



  • dsTny schrieb:

    @brotbernd: Du hast mich falsch verstanden 🙂 Meine Frage war nicht, wie ich diesen Algorithmus schreiben kann, sondern wie ich die If-Abfrage ("if (BreakOnInvalid())" mitsamt else-Zweig) "vereinheitlichen" kann, sodass das nur ein Mal im Code steht und ich dann die Art Funktion immer nur aufrufe.

    Steht da doch nur einmal

    bool IsValid(Data& data)
    {
      if (data.A < minA)
        return false;
      if (data.B < minB)
        return false;
      return true;
    }
    
    ...
    
    for(;;)
    {
    data = Read();
    if (IsValid(data))
    {
     if (BreakOnInvalid())
        break;
     else
        continue;
    }
    Store(data);
    

    Du hast eine Methode, die überprüft ob die Daten gültig sind. Wenn diese False zurückgibt, wird an einer stelle entschieden, ob abgebrochen wird oder der Datensatz übersprungen wird.
    Wenn es darum geht die vielen Bedingungen in InValid flexibler zu gestalten, kannst Du das Specification Pattern anwenden. Jede Bedingung ist ein Objekt, das Du jeder Zeit zur IsValid Überprüfung hinzufügen kannst.

    http://ideone.com/lbY1x

    In dem Beispiel ist es jetzt sehr einfach implementiert. Wenn es komplexere Zusammenhänge gibt kann man noch die boolschen Verknüpfungen wie auf der Wiki Seite gezeigt implementieren. Der Aufwand lohnt sich aber wohl nur, wenn man ein wirklich flexibles System benötigt, z.B. wenn die Bedingungen erst zur Laufzeit festgelegt werden.

    Deinen Link konnte ich hier leider nicht öffnen..



  • dsTny schrieb:

    @pumuckl: Gut getroffen! Aber wie mache ich es dann, dass er in der "Haupt"-Funktion, wenn der User es so wünscht, den momentanen Durchgang abbricht und nicht das gesamte Auslesen?

    suchst du das Schlüsselwort continue ?



  • Hallo und nochmals herzlichen Dank für die Antworten 😉

    @314159265358979: Die Idee ist gut, vielleicht könnte ich die etwas weiter ausweiten, danke!

    @brotbernd: Ich werde mir das mal näher anschauen. So wie sich das aber bislang anhört, würde es nicht in meine Vorstellung passen. Das Problem: Es werden viele Daten in etwa 7 Funktionen eingelesen (alle Funktionen stehen für andere Objekttypen). Dann würde folgendes nach jedem überprüfen, ob das Eingelesene valide ist, ausgeführt werden:

    if (BreakOnInvalid()) 
        break; 
     else 
        continue;
    

    ... und das ist das, was ich eigentlich nicht will 😉

    @pumuckl: "continue may only be used inside a loop, such as a for statement." <-- Das Problem ist dann: Wenn ich in einer Funktion entscheide, was zu tun ist, könnte ich dann kein continue benutzen (da sich die Funktion an sich ja nicht in der Schleife befindet), oder?

    Danke 🙂



  • Ich kapier dein Problem noch nicht ganz. Gib mal deinen aktuellen Beispielcode, bitte. Nicht alle 7 Funktionen, eher 2 oder 3, und die Ausleselogik nur andeuten, aber so, dass man sieht, wie deine Schleifen und if-Abfragen zusammenspielen.


Log in to reply