Kleines Testprogramm mit Interface und einer Usereingabe

Kotelettklopfer

Bekanntes Mitglied
Den ein oder anderen wird es vielleicht schon nerven, aber ... mir egal xP
Habe mal nach dem Interface Kapitel das Buch auf Seite gelegt und mal was rumprobiert.

Ziel war es, ein Programm zu schreiben, welches jeweils 2 Zahlen von 2 Usern abnimmt, diese addiert und dann das Ergebnis ausgibt.
Das wollte ich per Vererbung und / bzw. mit Interface abbilden.

Das kam bei raus (klappt)...
[CODE lang="java" title="Main.java"]public class Main {
public static void main(String[] args) {
User1 a = new User1();
User2 b = new User2();

int zahl1 = a.zahl1();
int zahl2 = a.zahl2();
int zahl3 = b.zahl1();
int zahl4 = b.zahl2();

int total = zahl1 + zahl2 + zahl3 + zahl4;

System.out.println("Das Ergebnis lautet " + total);


}
}
[/CODE]


[CODE lang="java" title="Berechnung"]
public interface Berechnung {

public int zahl1();

public int zahl2();


}
[/CODE]


[CODE lang="java" title="User1.java"]import java.util.Scanner;

public class User1 implements Berechnung {

Scanner scanner = new Scanner(System.in);


@Override
public int zahl1() {
System.out.println("Geben Sie Zahl 1 für User 1 ein");
int zahl1 = scanner.nextInt();
return zahl1;

}

@Override
public int zahl2() {
System.out.println("Geben Sie Zahl 2 für User 1 ein");
int zahl2 = scanner.nextInt();
return zahl2;
}
}[/CODE]


[CODE lang="java" title="User2.java"]import java.util.Scanner;

public class User2 implements Berechnung {
Scanner scanner = new Scanner(System.in);

@Override
public int zahl1() {
System.out.println("Geben Sie Zahl 1 für User 2 ein");
int zahl1 = scanner.nextInt();
return zahl1;

}

@Override
public int zahl2() {
System.out.println("Geben Sie Zahl 2 für User 2 ein");
int zahl2 = scanner.nextInt();
return zahl2;

}


}
[/CODE]






Wollte mal fragen ob ihr euch den Code mal anschauen wollt und eventuelle Verbesserungen / Fehler aufzeigen könnt.
Ich habe hier mehr oder weniger bewusst auf englische Variablen etc. verzichtet, würde dies im Echtbetrieb aber tun.

Sorry wenn meine Beiträge oder die Anzahl den ein oder anderen stören könnten. Brauche nur viel Feedback um zu wissen, ich bin noch auf dem richtigen Weg. Das ist leider meine Art zu lernen 🙂 Nehmt es mir nicht krumm.
 
Was ist denn der Unterschied zwischen User1 und User2, weshalb dafür zwei Klassen nötig sind? Unterschiedliche Klassen bedeuten ja üblicherweise unterschiedliches Verhalten, siehst du das hier? 🙂


Generell ist es auch immer gefährlich, mehr als einen Scanner mit der gleichen Quelle zu erstellen, da sie intern Daten cachen.
 
Was ist denn der Unterschied zwischen User1 und User2, weshalb dafür zwei Klassen nötig sind? Unterschiedliche Klassen bedeuten ja üblicherweise unterschiedliches Verhalten, siehst du das hier? 🙂


Generell ist es auch immer gefährlich, mehr als einen Scanner mit der gleichen Quelle zu erstellen, da sie intern Daten cachen.

Ok, ich muss zugeben durchdacht war meine "Lern und Test" - APP scheinbar nicht, aber ich brauchte auf die schnelle etwas wo ich einfach mal probieren kann wie so ein Interface funktioniert daher zwei Klassen mit selbem inhalt.


Das mit dem Scanner versteh ich nicht ganz !?
Hätte hier jede Methode einen eigenen Scanner bekommen müssen?
 
Wenn man so ein Interface hat, dann entwickelt man auch 'dagegen'.

Also statt
Java:
User1 a = new User1();
User2 b = new User2();
Würde man eher schreiben:
Java:
Berechnung a = new User1();
Berechnung b = new User2();

Das Problem mit dem Scanner ist, dass er auch einen Puffer hat. Der eine Scanner kann also schon etwas eingelesen haben, das eigentlich schon für den nächsten gedacht ist.

Daher wäre ein zentraler Scanner ggf. besser.
 
Wenn man so ein Interface hat, dann entwickelt man auch 'dagegen'.

Also statt
Java:
User1 a = new User1();
User2 b = new User2();
Würde man eher schreiben:
Java:
Berechnung a = new User1();
Berechnung b = new User2();

Das Problem mit dem Scanner ist, dass er auch einen Puffer hat. Der eine Scanner kann also schon etwas eingelesen haben, das eigentlich schon für den nächsten gedacht ist.

Daher wäre ein zentraler Scanner ggf. besser.
Ah, das bedeutet ich erstelle ein Objekt User mit der Referenz Berechnung richtig?
 
Das mit dem Scanner versteh ich nicht ganz !?

Mal als Beispiel-Code:
Java:
import java.io.StringReader;
import java.util.Scanner;

class Scratch {
    public static void main(String[] args) {
        StringReader stringReader =  new StringReader("1 2 3 4"); // Äquivalent zu System.in als Quelle und "1 2 3 4" eingeben

        Scanner scanner1 = new Scanner(stringReader);
        Scanner scanner2 = new Scanner(stringReader);

        System.out.println("scanner1.nextInt() = " + scanner1.nextInt());
        System.out.println("scanner2.nextInt() = " + scanner2.nextInt());
    }
}

Was wird wohl ausgegeben? 🙂

scanner1. nextInt() liest die ganze Zeile ein, gibt davon aber dann nur die erste Zahl aus. Die "Quelle" ist damit "leer", und wenn scanner2 anfängt zu lesen, ist da "nichts" mehr, und scanner2.nextInt() schlägt fehl und wirft eine Exception.
 
Mal als Beispiel-Code:
Java:
import java.io.StringReader;
import java.util.Scanner;

class Scratch {
    public static void main(String[] args) {
        StringReader stringReader =  new StringReader("1 2 3 4"); // Äquivalent zu System.in als Quelle und "1 2 3 4" eingeben

        Scanner scanner1 = new Scanner(stringReader);
        Scanner scanner2 = new Scanner(stringReader);

        System.out.println("scanner1.nextInt() = " + scanner1.nextInt());
        System.out.println("scanner2.nextInt() = " + scanner2.nextInt());
    }
}

Was wird wohl ausgegeben? 🙂

scanner1. nextInt() liest die ganze Zeile ein, gibt davon aber dann nur die erste Zahl aus. Die "Quelle" ist damit "leer", und wenn scanner2 anfängt zu lesen, ist da "nichts" mehr, und scanner2.nextInt() schlägt fehl und wirft eine Exception.
Ok, verstehe ich in dem Fall, aber bei meinem Beispiel wird doch 4 mal nach einer neuen Eingabe gefragt. Wäre das nicht etwas anderes?
Müsste ich so einen zentralen Scanner (Kneitzel sprach sowas an) dann in einer separaten Klasse betreiben?
 
Müsste ich so einen zentralen Scanner (Kneitzel sprach sowas an) dann in einer separaten Klasse betreiben?
Betreiben ist der falsche Ausdruck. Du erzeugst ein Scanner-Objekt und zwei User-Objekte. Wenn das User-Objekt einen Scanner benötigt, der User also abhängig vom Scanner ist, dann erzeugt das User-Objekt den Scanner nicht einfach selbst, sondern verwendet einen gegebenen.

Wie im richtigen Leben: wenn Du etwas einscannen willst, dann baust Du Dir nicht erstmal einen Scanner, sondern verwendest einen, der von anderen Leuten gebaut wurde.

Genauso läuft das hier auch ab:
Java:
Scanner sc = new Scanner(System.in);

User user1 = new User(sc);
User user2 = new User(sc);
Hier wird der Scanner direkt beim Bauen der User-Objekte an den Konstruktor der User-Klasse übergeben. Der Scanner ist dann eine Instanzvariable von User und kann von den Methoden zahl1() und zahl2() verwendet werden.
 
@Kotelettklopfer
Mal eine Frage zum Verständnis: Du müßtest ja eigentlich vorher das Kapitel mit den Klassen durchgeackert haben.

Hast du denn verstanden, was eine Klasse ist? Bzw. was hast du denn verstanden, was eine Klasse sein soll?

Dein Code ist zwar richtig, aber doch irgendwie...naja...er zeigt halt formal wie man ein Interface verwendet, aber Sinn und Zweck eines Interfaces kommt da nicht so richtig durch, daher die Frage. Wie gesagt, wenn ich mich recht erinnere werden Interfaces in dem Buch noch nicht so recht erklärt, aber so ein bisschen sollte man es doch verstehen...sonst werden die Swing-Beispiele am Ende gar zu mühsam.
 
Betreiben ist der falsche Ausdruck. Du erzeugst ein Scanner-Objekt und zwei User-Objekte. Wenn das User-Objekt einen Scanner benötigt, der User also abhängig vom Scanner ist, dann erzeugt das User-Objekt den Scanner nicht einfach selbst, sondern verwendet einen gegebenen.

Wie im richtigen Leben: wenn Du etwas einscannen willst, dann baust Du Dir nicht erstmal einen Scanner, sondern verwendest einen, der von anderen Leuten gebaut wurde.

Genauso läuft das hier auch ab:
Java:
Scanner sc = new Scanner(System.in);

User user1 = new User(sc);
User user2 = new User(sc);
Hier wird der Scanner direkt beim Bauen der User-Objekte an den Konstruktor der User-Klasse übergeben. Der Scanner ist dann eine Instanzvariable von User und kann von den Methoden zahl1() und zahl2() verwendet werden.
Ich bekomme das so nicht in meinen Klassen abgebildet bzw. weiß nicht genau wie.
Wo soll Scanner sc = new Scanner rein ?
Wenn ich das in der Main einbaue, sagt er mir es werden 0 Parameter erwartet aber 1 übergeben.



Wäre das nicht auch so möglich? Ich habe den Scanner in das Interface eingebaut und rufe dann in den User Klassen sc.nextInt auf

[CODE lang="java" title="Berechnung.java"]import java.util.Scanner;

public interface Berechnung {
Scanner sc = new Scanner(System.in);


public int zahl1();

public int zahl2();


}[/CODE]

[CODE lang="java" title="User1.java"]public class User1 implements Berechnung {


@Override
public int zahl1() {
System.out.println("Geben Sie Zahl 1 für User 1 ein");
int zahl1 = sc.nextInt();
return zahl1;

}

@Override
public int zahl2() {
System.out.println("Geben Sie Zahl 2 für User 1 ein");
int zahl2 = sc.nextInt();
return zahl2;
}
}[/CODE]
 
@Kotelettklopfer
Mal eine Frage zum Verständnis: Du müßtest ja eigentlich vorher das Kapitel mit den Klassen durchgeackert haben.

Hast du denn verstanden, was eine Klasse ist? Bzw. was hast du denn verstanden, was eine Klasse sein soll?

Dein Code ist zwar richtig, aber doch irgendwie...naja...er zeigt halt formal wie man ein Interface verwendet, aber Sinn und Zweck eines Interfaces kommt da nicht so richtig durch, daher die Frage. Wie gesagt, wenn ich mich recht erinnere werden Interfaces in dem Buch noch nicht so recht erklärt, aber so ein bisschen sollte man es doch verstehen...sonst werden die Swing-Beispiele am Ende gar zu mühsam.
Ehrlich gesagt glaube ich, ist von allem nur ein Bruchteil übrig geblieben.
Wenn du mich jetzt so fragst... könnte ich keine vernünftige Antwort geben.
 
Wenn ich das in der Main einbaue, sagt er mir es werden 0 Parameter erwartet aber 1 übergeben.
Du musst natürlich auch die jeweilige Methode anpassen, so dass ein Scanner Objekt erwartet wird.

Und wenn Du den Scanner als Feld definierst, dann bekommt jede Instanz doch wieder eine eigene Instanz. Und genau das soll doch verhindert werden.

Ansonsten auch noch generell mein Senf zu dem Topic (Hatte ich in der Vergangenheit auch schon einmal erläutert):
Prinzipiell ist es denkbar, immer einen neuen Scanner auf System.in zu erstellen. Dies hat den Vorteil, dass es eben keinerlei "Überhang" gibt.
Sprich: Du erwartest ein int aber der User gibt kein int ein. Dann muss man den Text, der eingegeben wurde, erst ausgelesen werden (nextLine). Wenn man aber immer einen neuen Scanner erzeugt, dann hat man in der Regel immer einen sauberen Stand.

Das Problem ist aber, dass die Applikation sich dann nicht mehr so verhält, wie man das erwartet. Denn es geht ja um eine Konsolen Applikation und da kann man die Eingabe auch z.B. aus einer Datei rein schicken. Und dann ist das Verhalten nicht vorher zu sagen. Eine große Datei wird der Scanner nicht komplett laden. Also hat er eine gewisse Anzahl an Zeichen gelesen und die sind dann weg aus dem Stream. Das Verhalten wird also richtig lustig.

==> Daher ganz klar: Nicht machen in einer Applikation. So es nur um reine Trainigs-Elemente geht, dann mag es egal sein, da so eine Funktionalität nicht gefordert ist. Aber es wird ein Pattern erlernt, das einfach falsch ist.

Da wäre es besser, in einer Klasse Deiner Wahl einfach ein
public static final Scanner userInputScanner = new Scanner(System.in);
zu setzen. Oder da es eine Konstante ist, dann vom Naming her halt ein:
public static final Scanner USER_INPUT_SCANNER = new Scanner(System.in);

Oder Du machst es private und dann noch ein getter:
public static Scanner getUserInputScanner() { return userInputScanner; }
 
Wenn ich das in der Main einbaue, sagt er mir es werden 0 Parameter erwartet aber 1 übergeben.
Ja, weil Du einen entsprechenden Konstruktor in User brauchst:
Java:
class User implements Berechnung {
    private final Scanner sc;

    public User(Scanner scanner) { // Konstruktor, der bei new User(einScanner) aufgerufen wird
        this.sc = scanner;
    }

    @Override
    public int zahl1() {
        System.out.println("Geben Sie Zahl 1 für User 1 ein");
        int zahl1 = sc.nextInt();
        return zahl1;

    }

    @Override
    public int zahl2() {
        System.out.println("Geben Sie Zahl 2 für User 1 ein");
        int zahl2 = sc.nextInt();
        return  zahl2;
    }
}

Jetzt kannst Du in main z. B. schreiben
Java:
Scanner sc = new Scanner(System.in);

User user1 = new User(sc);
User user2 = new User(sc);
und, weil User das Interface Berechnung implementiert, auch etwas wie
Java:
Scanner sc = new Scanner(System.in);

Berechnung berechnung1 = new User(sc);
Berechnung berechnung2 = new User(sc);
 
Habe es jetzt in meinen beiden User Klassen und der Main angepasst.

Java:
import java.util.Scanner;

public class User1 implements Berechnung {
    private final Scanner sc;

    public User1(Scanner scanner) {
        this.sc = scanner;
    }



    @Override
    public int zahl1() {
        System.out.println("Geben Sie Zahl 1 für User 1 ein");
        int zahl1 = sc.nextInt();
        return zahl1;

    }

    @Override
    public int zahl2() {
        System.out.println("Geben Sie Zahl 2 für User 1 ein");
        int zahl2 = sc.nextInt();
        return zahl2;
    }
}



Werde mir wohl die ersten Kapitel doch noch einmal ansehen müssen, scheinbar ist nicht viel hängen geblieben .
String Kopf = null;

Danke Euch
 
String Kopf = null;
Variablennamen sollten mit einem Kleinbuchstaben beginnen 🙂

scheinbar ist nicht viel hängen geblieben

Mach dir mal nicht zu viel "kopf". Gerade der Sinn von Interfaces erschließt sich einem Anfänger nicht auf Anhieb. Manchmal ist es besser nicht gleich den Sinn zu suchen, sondern erst mal auf sich zukommen zu lassen. Irgendwann (spätestens bei den Entwurfsmustern und SOLID) macht es dann "Klick".
 
String Kopf = null;
Das ist normal.

Mal ein paar Worte zum Interface: nehmen wir mal ein paar haushaltsübliche Dinge zur Hand, z. B. Nachttischlampe, Fernseher, Kaffeemaschine, Dein Smartphone, Computer, Auto, Atomreaktor usw.

Betrachtet man diese Dinge abstrakt genug, haben sie eine Gemeinsamkeit: man kann sie wenigstens ein- und ausschalten. Man könnte sagen, sie sind "schaltbar". Grundsätzlich bist Du damit in der Lage, jedes Gerät einschalten und ausschalten zu können. Natürlich ist die Umsetzung bei jedem Gerät anders, so kann man beim AKW nicht einfach den Kippschalter umlegen, aber das spielt keine Rolle, denn auf abstrakter Ebene bleibt es dabei: man kann das Ding ein- und ausschalten.

Theoretisch könnte man alle Geräte mit z. B. einem Infrarotsensor ausstatten, so dass sich alle Geräte mit einer einzigen Fernbedienung ein- und ausschalten lassen. Beim AKW könnte die Fernbedienung dafür sorgen, dass eine Meldung im Kontrollraum eingeht und die Leute dort den Abschaltprozess durchführen oder das Teil hochfahren.

Genau das macht ein Interface:
Java:
public interface Schaltbar {
    void schalteEin();
    void schalteAus();
}
Der Benutzer dieses Interfaces muss sich nicht dafür interessieren, was beim Ein- und Ausschalten passiert. Er muss nur wissen, dass schalteEin() das Gerät einschaltet und schalteAus() das Gerät abschaltet und schon kann er das Teil bedienen - wie bei der Fernbedienung oben.

Im Programm kann so ein Benutzer z. B. ein Button auf der Oberfläche sein. Das kann ein normaler Button oder ein TogggleButton sein. Ebenso möglich wäre z. B. eine Dropdown-Liste, eine CheckBox, ein RadioButton. Natürlich muss der Benutzer kein Element der Oberfläche sein. Es kann sich z. B. um einen Timer handeln oder um einen Webservice, eine Konsoleneingabe, Kommandozeilenparameter. Ganz egal.

Der Benutzer muss noch nicht einmal wissen, was für ein Gerät er da schaltet. Genauso wie ich Dir eine Fernbedienung in die Hand drücken und Du schaltest ein oder aus. Gebe ich Dir die Fernbedienung für den Fernseher, schaltest Du diesen, gebe ich Dir dir Fernbedienung für die Kaffeemaschine, dann eben diese.

Und genau dafür hast Du Interfaces: jedes Objekt, das die Schaltbar-Schnittstelle anbietet, kann über die beiden Methoden ein- oder ausgeschaltet werden und der Benutzer (Client Code) muss nicht wissen, um welches Gerät es sich tatsächlich handelt. Den interessiert nur die Schaltbar-Schnittstelle.
 

Neue Themen


Zurück
Oben