Java Befehle von Konsolenausgabe, "elegante" Lösung?

Bender86

Lieutenant
Registriert
Jan. 2007
Beiträge
718
Hallo zusammen,

ich möchte grade ein kleines Programm schreiben, in dem Befehle von der Konsole eingelesen und ausgeführt werden. Die Befehle sind ja nun in String Form und in Abhängigkeit welcher String es war wird eine Methode aufgerufen. Mir fällt im Moment nur diese Möglichkeit ein:

Code:
if(cmd.compareTo("Befehl1") == 0) {
    methode1();
} else if(cmd.compareTo("Befehl2") == 0) {
    methode2();
} else if(cmd.compareTo("Befehl3") == 0) {
    methode3();
} else if
    ...
    ...
    ...
} else {
    System.err.println("Befehl wurde nicht erkannt, bitte erneut versuchen.");
}

Das ganze ist ja nun tierisch unschön. Mir ist sonst nur ein switch-case Block eingefallen, der ja aber nicht bei Strings verwendet werden kann.

Daher meine Frage, wie löst man sowas etwas eleganter als mit zig "else if"s?
 
Naja, also die einfachste Variante, die ich auch immer benutze und auch rel. übersichtlich finde vom Code her ist und bleibt die switch/case Anweisung. Das diese nicht mit String arbeitet, ist richtig, aber wie wärs, wenn du einfach deine Möglichkeiten vorher ausgibst und dann statt einem String ein int einliest... In etwa wie folgt:

Code:
System.out.println("1   -  Befehlname Nr.1);
System.out.println("2   -  Befehlname Nr.2);
System.out.println("3   -  Befehlname Nr.3);
System.out.println("4   -  Befehlname Nr.4);

//Auswahl einlesen
int auswahl = 0;

//Menüoptionen
switch(auswahl)

case 1: 
  Methodenaufruf für Auswahl 1
  ....
  break;

case 2:
  Methodenaufruf für Auswahl 2
  ....
  break;

 default
  ...


//usw...

Sprich du gibts vorher das Menü aus und lässt den User auswählen was er davon durchführen möchte.

Wenn das Menü immer wieder ausgegeben werden soll, bietet sich hier eine while Schleife an, in Verbindung mit einer boolean Variable die beispielsweise "fertig" oder so heissen könnte. Diese Möglichkeit das Programm zu beenden gibst du mit aus, in diesem Fall hab ich das mal als case 7 gedeutet... Meiner Meinung nach eine der geschicktesten Lösungen in deinem Fall.

Code:
boolean fertig;

while(fertig){

 System.out.println("1   -  Befehlname Nr.1);
 System.out.println("2   -  Befehlname Nr.2);
 System.out.println("3   -  Befehlname Nr.3);
 System.out.println("4   -  Befehlname Nr.4);

//Auswahl einlesen
 int auswahl = 0;

//Menüoptionen
 switch(auswahl)

 case 1: 
  Methodenaufruf für Auswahl 1
  ....
  break;

 case 2:
  Methodenaufruf für Auswah 2
  ....
  break;

 case 7:
  fertig = false;

 default 
  ...

}

//usw...

Wenn du Hilfe bei der Ausführung brauchst, sag bescheid.
 
Danke für den Hinweis. :)

Die Lösung ist aber leider nicht das was ich mir vorstelle. ;) Was ich haben möchte ist, dass man Konsoleneingaben wie in der Shell macht. Wenn da immer die Befehlsnummern ausgegeben werden (bzw. man sie ausgeben muss, weil man die Nummern nicht kennt) ist das irgendwie unschön.

Ich spiele im Moment mit dem Gedanken eine Methode zu schreiben um das "else if.." ein bisschen abzukürzen in der Form:

Code:
	public static boolean is(String ssrc, String sdest) {
		if(ssrc.compareTo(sdest) == 0) {
			return true;
		} else {
			return false;
		}
	}
Dann könnte ich beim "else if" schreiben:
Code:
if(is(cmd, "Befehl1")) {
    Methode1();
} else if(is(cmd, "Befehl2")) {
    Methode2();
} else if(is(cmd, "Befehl3")) {
...
...
...
} else {
// Unbekannter Ausdruck
}
Dann hätte ich wenigstens nur ein
Code:
if(is(cmd, "Befehl"))
statt
if(cmd.compareTo("Befehl") == 0)
Aber so 100% zufriedenstellend ist es auch nicht.
 
Könntest das ganze auch über Reflection lösen. ;) Sprich, die Eingabe entspricht dem Methodennamen. Dadurch kannst du die Eingabe in einem Block abwicklen, ganz ohne switch oder if-else. :D

ungefähr so:
Method method = getClass().getMethod(<hier die eingabe>, null);
method.invoke(this, null);
 
Zuletzt bearbeitet:
Äh Reflection? Davon höre ich grade zum ersten Mal. :)

Aber das sieht seeeehr interessant aus. :D

Was da gemacht wird ist einfach ein Method-Objekt erzeugen und dann aufrufen richtig? Und dann schreibt man einfach für jeden Befehl eine Methode? (was bei der if-else Lösung ja auch der Fall wäre.)

Das werde ich mir mal genauer ansehen, danke danke!
 
Alternativ könntest du dich auch mit den Konzepten von OOP befassen, dann würde dir auffallen das du einen Denkfehler hast :rolleyes:

Und die Reflecting-API für sowas zu verwenden tut ja auch schon fast weh.

Sowas lösst man sinnvollerweise über eine Map, nebenbei bemerkt zeugt ein switch-Statement bei OOP fast immer von einem Denkfehler!


Hier mal ein schematisches Beispiel:
Code:
public class Test {

    private interface Command {     
        public void doAction();
    }
    
    private static Map<String,Command> call;
   
    static {
        call = new HashMap<String, Command>();
        
        call.put("Befehl1", new Command() {
            public void doAction() {
                //....
            }
        });
        
        call.put("Befehl2", new Command() {
            public void doAction() {
                //....
            }
        });
        
        //....
    }
    

    public static void main(String[] args) {
        for(String iArg : args) {
            try {
                call.get(iArg).doAction();
            }
            catch( Exception e ) {
                //...    
            }
        } 
    }

}
 
Zuletzt bearbeitet:
Sorry für die späte Antwort...

also ich habe nun mal die Lösung von ag3nt implementiert und das klappt ganz gut. Danke für diesen Vorschlag! :)

So gut bin ich im Vererbungs und Schnittstellen Thema noch nicht drin und so Sachen wie Interfaces haben wir in den 2 Semestern Java die ich in der Uni hatte quasi nur angesprochen aber nie benutzt.

Eine Frage hätte ich noch zu dem static { ... }-Block. Ich weiß von static bisher nur, dass man es benutzt um zB Methoden einer Klasse auszuführen, ohne das man davon ein Objekt erzeugen muss. Heißt der static Block in diesem Fall, das beim Programmstart vor allem anderen erstmal die HashMap angelegt wird und die Commands eingefügt werden?
 
Korrekt, das ist der sogenannte Klassenkonstruktor. Sobald die Klasse das erste mal benutzt wird, wird dieser einmalig ausgeführt.
 
SheepShaver schrieb:
Könntest das ganze auch über Reflection lösen. ;) Sprich, die Eingabe entspricht dem Methodennamen. Dadurch kannst du die Eingabe in einem Block abwicklen, ganz ohne switch oder if-else. :D

ungefähr so:
Method method = getClass().getMethod(<hier die eingabe>, null);
method.invoke(this, null);

Tut mir Leid, dass ich hier so zwischenrede, aber gibt es diese Möglichkeiten auch für VB.net und C#?
Und kann man auch Objekte so ansprechen?
 
Jap, Reflection gibts auch unter C#. Such in Google einfach nach C# Reflection/Dynamic Method Invocation und du solltest fündig werden.

@ag3nt
Mein Vorschlag war natürlich nicht ganz ernst gemeint. Deswegen auch der Smilie.
 
SheepShaver schrieb:
Mein Vorschlag war natürlich nicht ganz ernst gemeint. Deswegen auch der Smilie.

Hmpf, das hättest du etwas eindeutiger machen können. :p Ich hatte das durchaus als ernst gemeinte Antwort aufgefasst und mir ein paar Sachen dazu durchgelesen, auch wenn ich dann letztenendes den Vorschlag von ag3nt benutzt habe.
 
Zurück
Oben