Machine d'état de séquence
J'ai essayé d'analyser les arguments de la ligne de commande. Le programme nécessite quatre arguments. Je répète les arguments. Si l'argument est une option, je traite l'option. Sinon, l'argument est l'un des arguments requis. Afin de lire les arguments requis, j'ai besoin d'une sorte de machine à états. Dans le premier cas, le premier argument doit être lu. Dans le second cas, le second argument et ainsi de suite.
J'ai écrit une Procclasse avec une seule méthode, qui renvoie à nouveau une Procclasse.
static abstract class Proc {
abstract Proc exec (String arg);
}
Par cela, je peux exécuter une action et définir ce qui doit être fait ensuite.
- enregistrer l'hôte de la base de données, puis lire le nom
- enregistrer le nom de la base de données, puis lire l'utilisateur
- enregistrer l'utilisateur de la base de données, puis lire le fichier xml
- enregistrer le fichier xml et puis rien
Mais à cause de tous les frais généraux de la classe, il est difficile à lire.
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;
}
};
}
};
}
};
}
};
Existe-t-il un moyen de simplifier le code? J'ai essayé Lambdas, mais il me semble que Lambdas ne peut utiliser que des variables finales, ce qui est un peu inutile, lorsque je veux stocker une valeur.
Exemple complet:
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);
}
}
Réponses
Tout d'abord, vous devez suivre les conventions de dénomination Java .
Deuxièmement, ne raccourcissez pas les noms simplement parce que vous le pouvez. Exemple, que signifie «Proc»? Procédure? Processeur? Même si les noms s'allongent, la lisibilité en vaut la peine!
static String db_host = null;
Vos membres ne devraient pas static, et devraient idéalement être qualifiés avec autre chose que package-private, comme protectedou privatepour montrer clairement l'intention.
Afin de lire les arguments requis, j'ai besoin d'une sorte de machine à états.
Est-ce une exigence qui vous a été donnée ou est-ce une hypothèse que vous aviez? Parce que ce n'est pas du tout vrai. Dans l'ensemble, votre système est complètement inutilement complexe sans raison ni avantage évident. Cela ne ressemble pas du tout à une machine à états, c'est juste une chaîne trop complexe d'appels de fonctions.
Une machine à états pour votre analyse d'argument de commande serait quelque chose comme ceci:
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;
}
}
Et même cela est étrangement complexe.
Ce que vous voulez, c'est la solution la plus simple qui fonctionne, et ce serait une extraction codée en dur des arguments:
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];
Ce qui n'est bien sûr pas joli, mais la solution la plus simple avec laquelle vous pouvez vous en tirer. Bien entendu, la longueur du tableau doit être vérifiée au préalable, qu'il s'agisse de 4 éléments ou plus. Ensuite, vous vérifierez si tous les paramètres sont définis, sinon, quittez avec une erreur.
Si vous voulez une solution plus sophistiquée, vous devez écrire vous-même un analyseur d'arguments complet, un exercice pas si trivial.