Best Practice Bankautomat

Java The Hutt

Mitglied
Hallo :)

Kurze Vorstellung meinerseits:

Ich began letzte Woche mein Informatikstudium und bin total von allem begeistert. Im ersten Semester lernen wir C, darauffolgend Java. Ich programmiere sehr gerne, auch wenn ich diese Leidenschaft erst vor 2 Wochen entdeckt habe. Demnach fehlen mir noch sehr viele Kenntnisse, ich arbeite jedoch stark daran, das fehlende Wissen schnellstmöglich zu füllen.

Einleitung:

Ich möchte gerne einen "Bankautomaten" Programmieren, welcher in der Console Werte und Sätze ausgibt (Vorerst ohne GUI). Der Nutzer soll wählen können, was er machen möchte. Ob "Guthabenabfrage" o. "Betrag abheben / einzahlen" - eben die typischen Sachen, die man an einem Bankautomaten erledigen kann.


Frage:

Welche Möglichkeiten habe ich, den Benutzer auswählen zu lassen, was er gerne tun möchte?
Ich hatte an eine Eingabe via Scanner gedacht, die auf die jeweiligen Methoden springt.
Beispiel: Drücke "A" für Abheben.
Ist dieser Grundgedanke machbar oder gibt es bessere/effizientere Wege? :)
Sowie möchte ich meinen bisherigen Code vorstellen, um zu erfahren, welche Verbesserungsmöglichkeiten es generell gibt (Lesbarkeit, Konventionen etc...)

Code bisher:
Main:
Java:
import java.util.Scanner;

public class Java {
   
    public static void main(String[] args) {
       
        System.out.println("Willkommen beim Bankautomatt!");
        System.out.println("");
       
       
        {
        Konto giro = new Konto ();
       
        giro.inhaber = "M";
        giro.guthaben = 2500;
        giro.nummer = 6500;
        giro.BLZ = 5800;
        giro.limit = -500;
       
        System.out.println(giro.inhaber);
        System.out.println("Ihr Kontostand "+ giro.guthaben +"€");
        System.out.println("Sie dürfen Ihren Betrag überziehen um " + (giro.limit*-1) + "€");
        System.out.println("");
       
        System.out.println("Bitte geben Sie den Betrag ein, den Sie abheben möchten!");
       
        Scanner betrag = new Scanner (System.in);
        double x = betrag.nextDouble();
       
        giro.abheben(x);
        System.out.println(giro.guthaben);
        betrag.close();
       
        }
    }
}


Konto class mit Abhebung:
Java:
public class Konto {

    String inhaber;
    double guthaben;
    int BLZ;
    int nummer;
    double limit;
   
    public boolean abheben (double betrag) {
        if (betrag < 0) { //abheben von negativen beträgen geht nicht
            System.out.println("Sie können keine Minusbeträge abheben!");
            System.out.print("Derzeitiger Kontostand: ");
           
            return false;
           
        }
        else if ((guthaben - betrag) >= limit) {
            guthaben = guthaben - betrag;
            System.out.println("Neuer Kontobetrag: ");
            return true; //abheben erfolgreich
        }
        else {
            System.out.println("Abheben nicht möglich, da Ihre Kontodeckung nicht ausreichend ist!");
            System.out.print("Derzeitiger Kontostand: ");
            return false; //Limit überzogen
        }   
        }
    }
 

mihe7

Top Contributor
Ich hatte an eine Eingabe via Scanner gedacht, die auf die jeweiligen Methoden springt.
Passt.

welche Verbesserungsmöglichkeiten es generell gibt
  1. Gib der Klasse "Java" einen sinnvolleren Namen.
  2. BLZ und Kontonummer sind out :)
  3. Variablen in lowerCamelCase - das gilt auch für BLZ.
  4. Du solltest einen Konstruktor erstellen, um zu verhindern, dass sinnfreie Konten erzeugt werden (kein Inhaber, keine BLZ, keine Kontonummer)
  5. In Konto keine Benutzerausgaben (= UI). Das löst man entweder via Exceptions oder über einen entsprechenden Rückgabewert. Für komplexere Rückgabewerte gibt es Objekte.
  6. Jetzt brauch ich Deinen Code:
Java:
        Scanner betrag = new Scanner ([URL='http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+system']System[/URL].in);
        double x = betrag.nextDouble();
       
        giro.abheben(x);

Der Name des Scanners ist schlecht gewählt. Warum? Weil es kein Betrag ist. Daher musst Du hinterher krampfhaft ein "x" für den Betrag verwenden.
Vergleich:
Java:
        Scanner eingabe = new Scanner(System.in);
        double betrag = eingabe.nextDouble();
        giro.abheben(betrag);
Liest sich doch gleich leichter.
 

Robat

Top Contributor
Ein paar kleine Anmerkungen meiner Seits:
- Schon mal sehr löblich, dass du versuchst dein Programm zu strukturieren. Beachte dabei aber das Geheimnisprinzip der OOP. Bedeutet, dass der direkte Zugriff auf Member einer Klasse immer soweit wie möglich eingeschränkt werden sollte und "nur" Zugriff über definierte Strukturen (Getter & Setter) möglich sein sollte. In deiner Klasse Konto solltest du also alle Membervariablen private machen und jeweils Getter & Setter nach bedarf anlegen
Java:
public void setOwner(String owner) {
    this.owner = owner;
}
- Scanner würde ich nicht "betrag" nennen .. er ist ja ggf. nicht nur für die Eingabe eines Betrages zuständig, sondern für mehrere Dinge ;)
- Anstatt die Daten eines Kontos immer wieder einzeln per System.out.println auszugeben, würde ich dir empfehlen, dass du dir mal das Überschreiben der toString() Methode anschaust. Das würde dir das Leben dahingehend erleichtern, dass du nur noch System.out.println(konto) schreiben müsstest und alle relevanten Daten formatiert ausgegeben werden.
 

Java The Hutt

Mitglied
Lieben Dank für die schnellen und hilfreichen Antworten! Ich werde mir alles zu Herzen nehmen, den hinsichtlich gegebener Verbesserungsmöglichkeiten abändern und das das ganze hier zeitnah erneut vorzeigen :)

/JavaTheHutt
 

cleanairs

Mitglied
Wenn Du die Setter schreibst, kannst Du in den Settern kontrollieren was der User eingibt und entsprechende Werte zulassen oder nicht. Super wichtig damit Du falsche Eingaben abfangen kannst!

Nutzbar dann vor Allem im Konstruktor.
Java:
public Konto( ..., String iban, ...) {
        ...
        setIban(iban);
        ...
}

Ein Beispiel: um dann sicher zu stellen, dass die eingegebene deutsche IBAN (die Du ja statt Konto/BLZ nehmen sollst) genau 22 Zeichen lang ist, wäre, im Konstruktor den übergebenen iban String oben im Konstruktor mit setIban(iban); zu checken:
Java:
public void setIban(String iban) {
        if(iban.length() != 22) {
            System.out.println("Eine deutsche IBAN muss genau 22 Zeichen lang sein!");
        }else
            this.iban = iban;
}

Besten Gruß.

Julian
 
Zuletzt bearbeitet:

Robat

Top Contributor
@cleanairs Im Setter (bzw generell in der Model Klasse) solltest du keine Ausgaben haben. Wirf lieber eine entsprechende Exception - so bist du losgelöst von der View
 

Robat

Top Contributor
View ist erstmal nur ein Sammelbegriff für deine visuelle Repräsentation der Daten. Das kann ja, wie hier, eine Konsolenausgabe, eine grafische Oberfläche oder auch eine Datei sein(oder andere Dinge). Vorteil ist, dass man das Model losgelöst von der View programmiert und somit, in der theorie, die view jeder Zeit austauschen kannst ohne das Model zu verändern.

Wenn du jetzt in den Setter eine Konsolenausgabe einbaust bist du nicht mehr losgelöst.. außerdem wäre die Konsolenausgabe bei einer grafischen Umsetzung relativ nutzlos ;)
 
Zuletzt bearbeitet:

Robat

Top Contributor
Java:
public void setIban(String iban) {
    if(!isValidIBAN(iban)) {
        throw new IllegalArgumentException(String.format("%s is not a valid IBAN", iban));
    }
    this.iban = iban;
}
Wie die Implementierung von boolean isValidIBAN(String) dann aussieht, sei mal dahin gestellt.
 

Robat

Top Contributor
Müssen wir jetzt wirklich diskutieren, was ich mit Validierung einer IBAN meine? Ich denke nicht.
 
Zuletzt bearbeitet:

mihe7

Top Contributor
Für die IBAN würde sich eine Klasse anbieten.

Java:
public class IBAN {
    private final String value;

    private IBAN(String value) {
        if (!IBAN.isValid(value)) {
            throw new IllegalArgumentException("Invalid IBAN '" + value + "'");
        }
        this.value = value.toUpperCase();
    }

    public static boolean isValid(String text) {
        if (text == null || text.length() < 5 || text.length() > 34) {
            return false;
        }
        int checksum = 0;
        int ix = 4;
        char[] chars = text.toUpperCase().toCharArray();
        for (int i = 0; i < chars.length; i++) {
            if ((chars[ix] < '0' || chars[ix] > '9') &&
                    (chars[ix] < 'A' || chars[ix] > 'Z')) {
                return false;
            }
            int value = chars[ix] - '0';
            if (value > 9) {
                value -= 7;
                checksum = (checksum * 10 + value / 10);
            }
            checksum = (checksum * 10 + value % 10) % 97;
            ix = (ix + 1) % chars.length;
        }
        return checksum == 1;
    }

    @Override
    public boolean equals(Object o) {
        if (o == null || o == this || !(o instanceof IBAN)) {
            return o == this;
        }
        IBAN iban = (IBAN) o;
        return value.equals(iban.value);
    }

    @Override
    public int hashCode() {
        return 7 + 3 * value.hashCode();
    }

    @Override
    public String toString() {
        return value;
    }
}
 

Java The Hutt

Mitglied
Ich bin es wieder :)
Die ersten 2 Studienwochen sind vergangen. Durch das Einleben dort hat das Projekt hier ein klein wenig geschliffen. Die zweite schlimme Nachricht, im ersten Semester nur C! :D

Anbei mein überarbeiteter Code!
Ich habe vorrangig einen Konstruktor hinzugefügt, sowie mit Switch Statement die Methoden angepeilt. Für´s Wochenende nun nehme ich mir noch vor, eine Datei einzulesen, die als erstes den Kontostand abfragt und abspeichert und wenn das gut klappt, die gesamten Informationen eines Kontoinhabers.
Danach möchte ich die Do-While Schleife mit "ESC" beenden. Mal Schauen ob es klappt :D
Anbei erstmal mein überarbeiteter Code!

Eine kurze Frage noch vorab, an welcher Stelle kann ich den Scanner schließen? Wenn ich ihn innerhalb der Schleife schließe, erhalte ich im nächsten Schleifen Durchgang eine Fehlermeldung, da er zuvor geschlossen wurde.

Java:
import java.util.Scanner;

public class Java {
   
    public static void main(String[] args) {
       
        Konto giro = new Konto ("JavaTheHutt", 2500, 650020, 5800303, -500 );             //Konto Konstruktor

        System.out.println    (    "Willkommen beim Bankautomatt!\n\n"
                +                 "Was möchten Sie machen," + giro.inhaber +    "?\n\n"
                +                 "Drücken Sie 0 um Kontoinformationen einzusehen\n"
                +                 "Drücken Sie 1 um Geld abzuheben\n"
                +                 "Drücken Sie 2 um Geld einzuzahlen"   
                            );
       
        int durchgang = 0;
        do {
           
            Scanner auswahl = new Scanner (System.in);
            int antwort = auswahl.nextInt();
       
       
       
            if ((antwort != 0) && (antwort != 1 ) && (antwort != 2 ))
                System.out.println("Bitte Zahlen zwischen 0, 1 und 2 eingeben!");
           
       
            switch (antwort){
       
            case 0:                                                                      // Kontoinformation
                System.out.println(    "Ihr Kontostand beträgt "        + giro.guthaben     + "€\n"
                        +             "Sie dürfen Ihren Betrag um "     + (giro.limit*-1)     + " überziehen!");
                    break;
       
            case 1:                                                                     // Abheben
                System.out.println("Bitte geben Sie den Betrag ein, den Sie abheben möchten!");   
                Scanner eingabe = new Scanner (System.in);
                double betrag = eingabe.nextDouble();
                giro.abheben(betrag);
                System.out.println(giro.guthaben);
                    break;
       
            case 2:                                                                     //Einzahlung
                System.out.println("Wie viel möchten Sie einzahlen?");
                Scanner einzahlung = new Scanner (System.in);
                double betrag1 = einzahlung.nextDouble();
                giro.einzahlen(betrag1);
                System.out.println("Sie haben erfolgreich " + betrag1 + "€ eingezahlt!");
                    break;
                            }
           
            }
            while ( durchgang <1);
        }
    }

Java:
public class Konto {

    String inhaber;
    double guthaben;
    int BLZ;
    int nummer;
    double limit;
                                                                                                    //Konstruktor: Mit Guthaben
    Konto (String i, double g, int n, int b, double l) {
        inhaber     = i;
        guthaben     = g;
        nummer        = n;
        BLZ            = b;
        limit        = l;
    }
   
    public boolean abheben (double betrag) {
        if (betrag < 0) {                                                                             //abheben von negativen beträgen geht nicht
            System.out.println("Sie können keine Minusbeträge abheben!\nDerzeitiger Kontostand:");
            return false;
        }
        else if ((guthaben - betrag) >= limit) {
            guthaben = guthaben - betrag;
            System.out.println("Neuer Kontobetrag: ");
            return true;                                                                             //abheben erfolgreich
        }
        else {
            System.out.println("Abheben nicht möglich, da Ihre Kontodeckung nicht ausreichend ist!\nDerzeitiger Kontostand: ");
            return false;                                                                             //Limit überzogen
        }   
    }

    public double einzahlen(double betrag) {
        guthaben = guthaben + betrag;
        return guthaben;
    }
   
}

Lieben Gruß und sei die Macht mit euch!\n
Java the Hutt :D
 
X

Xyz1

Gast
im ersten Semester nur C
Oh das ja recht trocken....
noch vorab, an welcher Stelle kann ich den Scanner schließen
gar nicht schließen, ist anzuraten....
und sei die Macht mit euch
ja mit dir auch.
sowie mit Switch Statement die Methoden angepeilt
switches über Strings sind eher suboptimal....
erhalte ich im nächsten Schleifen Durchgang eine Fehlermeldung, da er zuvor geschlossen wurde
ziehe das mar weiter nach oben.
 

mrBrown

Super-Moderator
Mitarbeiter
Eine kurze Frage noch vorab, an welcher Stelle kann ich den Scanner schließen? Wenn ich ihn innerhalb der Schleife schließe, erhalte ich im nächsten Schleifen Durchgang eine Fehlermeldung, da er zuvor geschlossen wurde.
Gar nicht ;)

Den Scanner zu schließen, würde auch System.in schließen, was man in Java nicht machen sollte. (warum man da nicht vorgebeugt hat, ist mir ein Rätsel...)

switches über Strings sind eher suboptimal....
Dann ist es ja Glück, dass er nur ein switch über einen int hat...
 

Ähnliche Java Themen

Neue Themen


Oben