Macchina a stati della sequenza
Ho provato ad analizzare gli argomenti della riga di comando. Il programma richiede quattro argomenti. Ripeto gli argomenti. Se l'argomento è un'opzione, elaboro l'opzione. Altrimenti l'argomento è uno degli argomenti obbligatori. Per leggere gli argomenti richiesti ho bisogno di una sorta di macchina a stati. Nel primo caso dovrebbe essere letto il primo argomento. Nel secondo caso il secondo argomento e così via.
Ho scritto una Proc
classe con un solo metodo, che restituisce nuovamente una Proc
classe.
static abstract class Proc {
abstract Proc exec (String arg);
}
In questo modo posso eseguire alcune azioni e definire cosa dovrebbe essere fatto dopo.
- salva host db e poi leggi nome
- salvare il nome del database e quindi leggere l'utente
- salva utente db e poi leggi il file xml
- salva il file xml e poi niente
Ma a causa di tutto il sovraccarico della classe è difficile da leggere.
Proc proc = new Proc () {
Proc exec (String arg) {
db_host = arg;
return new Proc () {
Proc exec (String arg) {
db_name = arg;
return new Proc () {
Proc exec (String arg) {
db_user = arg;
return new Proc () {
Proc exec (String arg) {
xml_file = arg;
return null;
}
};
}
};
}
};
}
};
C'è un modo per semplificare il codice? Ho provato Lambdas, ma mi sembra che Lambdas possa usare solo variabili finali, il che è un po 'inutile, quando voglio memorizzare un valore.
Esempio completo:
public class Import
{
static String db_host = null;
static String db_port = "5432";
static String db_name = null;
static String db_user = null;
static String xml_file = null;
static void usage ()
{
System.err.println ("Usage: Import [-p PORT] HOST DATABASE USER FILE");
}
static abstract class Proc {
abstract Proc exec (String arg);
}
static void parse_args (String[] args)
{
Proc proc = new Proc () {
Proc exec (String arg) {
db_host = arg;
return new Proc () {
Proc exec (String arg) {
db_name = arg;
return new Proc () {
Proc exec (String arg) {
db_user = arg;
return new Proc () {
Proc exec (String arg) {
xml_file = arg;
return null;
}
};
}
};
}
};
}
};
try {
for (int i = 0; i < args.length; i++)
switch (args[i]) {
case "-p":
db_port = args[++i];
break;
case "-h":
usage ();
break;
default:
proc = proc.exec (args[i]);
}
}
catch (Exception ex) {
throw new Error ("Can not parse args!", ex);
}
}
public static void main (String[] args)
{
parse_args (args);
System.err.println ("db_host: " + db_host);
System.err.println ("db_port: " + db_port);
System.err.println ("db_name: " + db_name);
System.err.println ("db_user: " + db_user);
System.err.println ("xml_file: " + xml_file);
}
}
Risposte
Innanzitutto, dovresti seguire le convenzioni di denominazione Java .
Secondo, non abbreviare i nomi solo perché puoi. Esempio, cosa significa "Proc"? Procedura? Processore? Anche se i nomi diventano più lunghi, la leggibilità ne vale la pena!
static String db_host = null;
I tuoi membri non dovrebbero essere static
, e dovrebbero idealmente essere qualificati con qualcos'altro che package-private
, come protected
o private
per mostrare chiaramente l'intento.
Per leggere gli argomenti richiesti ho bisogno di una sorta di macchina a stati.
È un requisito che ti è stato dato o è un'ipotesi che avevi? Perché non è affatto vero. Nel complesso, il tuo sistema è completamente inutilmente complesso senza una ragione o un vantaggio ovvio. Né sembra affatto una macchina a stati, è solo una catena eccessivamente complessa di chiamate di funzione.
Una macchina a stati per l'analisi degli argomenti del comando sarebbe qualcosa del genere:
for (int index = 0; index < args.length; index++) {
String arg = args[index];
if (arg.equals("-p") && databaseHost == null) {
arg = args[++index];
databasePort = arg;
} else if (databaseHost == null) {
databaseHost = arg;
} else if (databaseUsername == null) {
databaseUsername = arg;
} else if (databasePassword == null) {
databasePassword = arg;
} else if (inputFile == null) {
inputFile = arg;
}
}
E anche questo è stranamente complesso.
Quello che vuoi è la soluzione più semplice che funzioni, e sarebbe un'estrazione hardcoded di argomenti:
if (args[0].equals("-h")) {
printHelp();
return;
}
int portProvidedOffset = 0;
if (args[0].equals("-p")) {
databasePort = args[1];
portProvidedOffset = 2;
}
databaseHost = args[portProvidedOffset + 0];
databaseUsername = args[portProvidedOffset + 1];
databasePassword = args[portProvidedOffset + 2];
inputFile = args[portProvidedOffset + 3];
Il che, ovviamente, non è carino, ma la soluzione più semplice con cui puoi farla franca. Naturalmente, la lunghezza dell'array dovrebbe essere controllata in anticipo, sia che si tratti di 4 elementi o più. Successivamente dovresti controllare se tutti i parametri sono impostati, in caso contrario, esci con un errore.
Se vuoi una soluzione più sofisticata, dovresti scrivere un parser completo di argomenti, un esercizio non così banale.