2010-01-13 5 views
2

J'ai une liste des balises XML et une méthode pour chacun d'eux dans ma classe, obtenir cette étiquette comme argument et faire son travail. Donc, toutes les méthodes obtiennent la même entrée et je veux parcourir la liste des balises en appelant la méthode appropriée à chaque fois.Comment dois-je mettre en œuvre une carte de chaîne à la méthode en Java?

En Python, je l'ai fait avec un hachage de chaînes (noms de balises) à lambdas (self.methodName()) et je veux le traduire en Java.

Maintenant en Java, je ne peux pas (?) Faire un tel hachage et même ne peux pas utiliser de chaînes (noms de balises) dans une instruction switch (avec chaque branche appelant une certaine méthode). La possibilité d'utiliser une dizaine d'ifs semble horriblement moche et je cherche un meilleur moyen de coder cela.

Répondre

1

Qu'est-ce que les gens pensent de cela?

public static enum Tags { 
    TAG1, TAG2, TAG3 
} 

public class Stuff { 
    ... 
    switch (Tags.valueOf(str)) { 
    case TAG1: handleTag1(); break; 
    case TAG2: handleTag2(); break; 
    case TAG3: handleTag3(); break; 
    } 
} 

L'avantage est que c'est concise et efficace (au moins dans ce cas). L'inconvénient est que ce n'est pas si bon avec des étiquettes de cas mixtes et balises avec Java non personnages -identifier en eux;. par exemple « - » (vous devez soit abuser acceptées des conventions de style Java pour les identifiants membres enum, ou vous devez ajouter une méthode explicite de conversion de chaînes à ENUM à la déclaration enum.)

l'aide d'une instruction switch pour dispatching est le mal dans le livre de certains peuples.Mais dans ce cas, vous devez comparer ce que vous gagnez avec ce que vous perdez. Et je serais surpris si le dispatching polymorphe donnait un avantage significatif sur une instruction switch en termes d'extensibilité et de maintenabilité.

3

Mappez la chaîne à une instance de classe en instanciant des classes et en les enregistrant (probablement dans un hachage). Toutes les classes doivent bien sûr implémenter la même interface. Vous constaterez que si vous codez de cette façon, une meilleure structure commence à émerger de votre code - par exemple vous pourriez trouver cela où auparavant vous auriez pu utiliser 2, 3 ou 10 méthodes similaires pour faire des choses légèrement différentes, Maintenant, le fait que vous pouvez transmettre des données dans votre constructeur vous permet de tout faire avec une ou deux classes différentes à la place.

Cette interface et les classes qui l'implémentent (pour moi au moins) évoluent presque toujours en un ensemble complet de classes dont j'ai toujours eu besoin mais que je n'aurais pas reconnu autrement. D'une manière ou d'une autre, je n'ai jamais l'air de regretter d'avoir écrit du code "dur", mais je regrette presque toujours de choisir le chemin le plus facile.

+0

je pourrais transmettre des données à des méthodes avant aussi: tag 'lambda: self.method (tag)' et ' hash [tagname] (tag) ', maintenant j'ai besoin de 15 autres fichiers ... – Fluffy

+0

Oui, ou vous pourriez avoir quelque chose de lisible et extensible. Par exemple, si vous avez trouvé vos données "Méthode" nécessaires et une deuxième méthode liée, comment le réparer? Pour couronner le tout, mon point de vue était que le fait de le coder comme classes en premier vous montre souvent des trous dans votre modèle d'objet - des objets que vous auriez dû avoir tout le long mais qui ont manqué dans votre conception initiale. –

1

J'irais avec ce que Bill K a suggéré en ce qui concerne l'implémentation de la même interface. Mais si vous avez la question de vouloir appeler des méthodes avec des noms différents, vous pouvez essayer d'utiliser reflection et faire quelque chose comme ceci:

Method method = Foo.class.getDeclaredMethod("methodName", parametersTypes); // Get the method you want to call 
Foo foo = new Foo(); 
method.invoke(foo, args); // invoke the method retrieved on the object 'foo' with the given arguments 
0

vous pouvez appeler la méthode de réflexion en utilisant:

Class.getMethod

donc vous n'avez pas besoin d'un commutateur ou d'un ensemble de si.

+0

oh, vous ne pouvez pas utiliser la réflexion? viens downvoter. – pstanton

+0

Vous pourriez utiliser la réflexion pour implémenter un "Hello world!" programme. Si c'est une bonne approche, c'est une question différente. – jarnbjo

+0

donc la réflexion n'est utile que pour les programmes de bonjour maintenant. D'accord. – pstanton

-1

Une réponse indirecte: XML représente généralement des données, pas d'instructions. Il est donc probablement plus utile de mapper la gestion de l'analyseur sur les champs. C'est ce que fait JAXB. Je suggère d'utiliser JAXB ou similaire. À moins que vous ayez une énorme quantité à faire, je déconseille fortement de réfléchir dans une langue à typage statique. Une chaîne de } else if (tag.equals("blah")) { (ou avec l'internement, } else if (tag == "blah") { ne va pas vous tuer.) Vous pouvez même mapper des chaînes sur leurs noms d'enum, mais c'est un petit peu réfléchi, vous devriez être avec nous dans JDK7

0

Voici un exemple de la proposition du projet de loi K (si je l'ai compris à droite)

public class Example { 

    static interface TagHandler { 
     void handle(String tag); 
    } 

    static final Map<String, Example.TagHandler> tagHandlers = new HashMap<String, Example.TagHandler>() { 
     { 
      put("tag_1", new Example.TagHandler() { 
       public void handle(String tag) { 
        System.out.println("Handling tag_1: " + tag); 
       } 
      }); 

      put("tag_2", new Example.TagHandler() { 
       public void handle(String tag) { 
        System.out.println("Handling tag_2: " + tag); 
       } 
      }); 
     } 
    }; 

    public static void main(String[] args) { 

     String[] tags = { "tag_1", "tag_2", "tag_1" }; 

     for (String tag : tags) { 
      tagHandlers.get(tag).handle(tag); 
     } 
    } 
} 
Questions connexes