2010-09-13 7 views
0

En Java, est-il possible d'associer un objet (c'est-à-dire un String) à une fonction à appeler?Définition d'une fonction de rappel pour une valeur donnée

j'ai deux menus similaires et les deux ont un onClickListener avec un code comme ceci:

if (item.id==0) { 
doSomeFunction(argument); 
} 
else if (item.id==1) { 
doSomeOtherFunction(); 
} 
else if (item.id==2) { 
doStuff(arg2); 
} 
else { 

} 

Je voudrais juste avoir un objet (c.-à-Hashtable) qui me permettrait de définir des associations entre « l'article. id "->" code à exécuter ".

Exemple:

0 -> doSomeFunction(argument); 
1 -> doSomeOtherFunction(); 
2 -> doStuff(arg2); 

En conséquence, je ne pouvais ignorer ces conditionals et juste effectuer un appel de fonction de la fonction stockée pour une item.id. donnée Par exemple, avec Lisp, je pourrais associer l'item.id à une fonction, puis utiliser "funcall" de Lisp pour appeler cette fonction.

Existe-t-il un moyen standard de faire quelque chose comme ça en Java?

Existe-t-il des solutions alternatives pour ignorer les conditions?

Veuillez noter que les fonctions appelées peuvent avoir besoin de recevoir des paramètres.

Merci.

Répondre

3

Comme il semble que vos fonctions n'ont pas besoin de renvoyer de valeurs, vous pouvez associer chaque clé ID à un objet Runnable qui appelle la méthode souhaitée. Par exemple:

Map<Integer, Runnable> map = ...; 
map.put(0, new Runnable() { 
    public void run() { 
    doSomeFunction(); 
    } 
}); 

map.get(0).run(); 

Si vous avez besoin des méthodes pour pouvoir retourner une valeur, vous pouvez utiliser Callable plutôt que Runnable. Vous pouvez également créer votre propre interface similaire et l'utiliser à la place si nécessaire.

Actuellement en Java, ce genre de chose doit être fait avec une instance d'une classe avec une seule méthode abstraite telle que Runnable. Java 7 ou 8 (selon la façon dont ils décident de procéder) ajoutera des expressions lambda et des références de méthode, ce que je pense être ce que vous voulez vraiment. Les références de méthode vous permettraient de faire quelque chose comme ça (en utilisant un Map<Integer, Runnable> comme ci-dessus).

map.put(0, Foo#doSomeFunction()); 

Modifier:

Votre mise à jour indique que certaines de ces méthodes aurait besoin d'avoir des arguments qui leur sont transmises. Cependant, vous semblez demander deux choses différentes. Dans votre exemple, de déclarer la mise en correspondance

0 -> doSomeFunction(argument); 
1 -> doSomeOtherFunction(); 
2 -> doStuff(arg2); 

les arguments sont spécifiés, ce qui indique qu'ils sont des valeurs qui sont disponibles au moment où vous déclarez la cartographie ou ils sont des champs dans la classe ou une telle. Dans les deux cas, vous seriez en mesure de les déclarer lorsque vous créez le Runnable:

new Runnable() { 
    public void run() { 
    doSomeFunction(argument); 
    } 
} 

Ici, argument aurait soit besoin d'être un champ ou être déclaré final.

Si, en revanche, vous n'avez pas de références aux arguments au moment de la création du mappage, vous devrez créer une interface cohérente que tous les appels de méthodes pourraient partager. Par exemple, la moindre interface commune qui pourrait fonctionner pour votre échantillon serait celui qui a déclaré deux paramètres et un void retour:

public interface CustomRunnable<T,G> { 
    public void run(T arg1, G arg2); 
} 

alors vous pourriez avoir:

map.put(0, new CustomRunnable<Foo,Bar>() { 
    public void run(Foo arg1, Bar arg2) { 
    doSomeFunction(arg1); 
    } 
}); 
map.put(1, new CustomRunnable<Foo,Bar>() { 
    public void run(Foo arg1, Bar arg2) { 
    doSomeOtherFunction(); 
    } 
}); 
map.put(2, new CustomRunnable<Foo,Bar>() { 
    public void run(Foo arg1, Bar arg2) { 
    doStuff(arg2); 
    } 
}); 

Chaque CustomRunnable utilise uniquement les arguments dont il a besoin, le cas échéant. Ensuite, vous pouvez faire l'appel comme ceci:

map.get(item.id).run(argument, arg2); 

, c'est évidemment obtenir assez laid, mais il est à peu près ce que vous avez à faire dans ce cas.

+0

+1 pour les exemples intéressants et pour noter les possibles Lambda en Java 7/8. – MyNameIsZero

1

Oui, il existe plusieurs façons de procéder. Un exemple est d'implémenter une interface anonyme et le stocker dans un HashMap, quelque chose comme ceci:

public class MyListeningClass 
{ 
    ... 

    public interface MyEventHandler 
    { 
     public void handle(String myParam); 
    } 

    private HashMap<ItemType, MyEventHandler> eventHandlers= new HashMap<ItemType, MyEventHandler>(); 

    initItems() 
    { 
     //do for each item 
     eventHandlers.put(item1, new MyEventHandler(){public void handle(String myParam){ 
        //do whatever I want to 
       }}); 
    } 

    myListeningMethod(ItemType item) 
    { 
     eventHandlers.get(item).handle("a parameter"); 
    } 
} 
0

Java Swing façon de répondre à cette classe est d'action. il suit fondamentalement le modèle de commande ...

1

La chose habituelle à faire est d'ajouter un autre programme d'écoute d'action (commande) sur chaque élément de menu, implémenté comme une classe interne anonyme courte. Malheureusement, la syntaxe est actuellement verbeuse et cela ne facilite pas le démarrage, mais c'est toujours la meilleure approche.

Vous ne dites pas quelle bibliothèque vous utilisez. onClickListener n'est pas Swing, mais si vous utilisiez Swing, vous voudriez JMenuItem.addActionListener.

+0

La bibliothèque que j'utilise est celle qui appartient à "Android" (OS mobile). Merci. – MyNameIsZero