J’ai une méthode qui est à une dizaine de lignes de code. Je veux créer des méthodes plus que faire exactement la même chose, sauf pour un petit calcul qui va changer une seule ligne de code. Il s’agit d’une application parfaite pour passer un pointeur de fonction pour remplacer que d’une ligne, mais Java n’est pas des pointeurs fonction. Ce qui est ma meilleure alternative ?
Réponses
Trop de publicités?Classe interne anonyme
Dites vous voulez avoir une fonction passée en avec un param qui retourne un
.
Tout d’abord il faut définir une interface avec la fonction que son seul membre, si vous ne pouvez pas réutiliser un existant.
Une méthode qui utilise le pointeur accepterait seulement `` instance comme suit :
Et serait appelé comme suit :
Pour chaque "pointeur de fonction", j'aimerais créer un petit foncteur de la classe qui implémente le calcul. Définir une interface que toutes les classes se mettre en œuvre, et de passer des instances de ces objets dans votre plus grande fonction. C'est une combinaison de "modèle de commande", et "modèle de stratégie".
@sblundy l'exemple est bon.
Lorsqu’il y a un nombre prédéfini de différents calculs, que vous pouvez le faire qu’une seule ligne, à l’aide d’un enum est un moyen rapide, encore clair moyen d’implémenter un modèle de stratégie.
De toute évidence, la déclaration de méthode de stratégie, mais aussi exactement une seule instance de chaque application est tous définis dans une classe ou un fichier unique.
Vous avez besoin de créer une interface qui fournit la fonction(s) que vous souhaitez passer. par exemple:
/**
* A simple interface to wrap up a function of one argument.
*
* @author rcreswick
*
*/
public interface Function1<S, T> {
/**
* Evaluates this function on it's arguments.
*
* @param a The first argument.
* @return The result.
*/
public S eval(T a);
}
Ensuite, lorsque vous avez besoin de passer une fonction, vous pouvez implémenter cette interface:
List<Integer> result = CollectionUtilities.map(list,
new Function1<Integer, Integer>() {
@Override
public Integer eval(Integer a) {
return a * a;
}
});
Enfin, la fonction map utilise le passé dans Fonction1 comme suit:
public static <K,R,S,T> Map<K, R> zipWith(Function2<R,S,T> fn,
Map<K, S> m1, Map<K, T> m2, Map<K, R> results){
Set<K> keySet = new HashSet<K>();
keySet.addAll(m1.keySet());
keySet.addAll(m2.keySet());
results.clear();
for (K key : keySet) {
results.put(key, fn.eval(m1.get(key), m2.get(key)));
}
return results;
}
Vous pouvez souvent utiliser Exécutable au lieu de votre propre interface si vous n'avez pas besoin de passer des paramètres, ou vous pouvez utiliser diverses autres techniques pour faire les param comptent moins "fixe", mais il est généralement un compromis avec la sécurité de type. (Ou vous pouvez surcharger le constructeur de votre fonction de l'objet à transmettre dans les params de cette façon.. il y a beaucoup d'approches, et certains fonctionnent mieux dans certaines circonstances.)
Vous pouvez également le faire (ce qui, dans certains RARES occasions de sens). Le problème (et c'est un gros problème) c'est que vous perdez tous les typesafety de l'utilisation d'une classe ou interface et vous avez à traiter le cas où la méthode n'existe pas.
Il a l ' "avantage" que vous pouvez ignorer les restrictions d'accès et d'appeler les méthodes privées (non illustré dans l'exemple, mais vous pouvez appeler les méthodes que le compilateur ne serait pas normalement vous permettre d'appeler).
Encore une fois, c'est un cas rare que cela fait sens, mais à ces occasions, il est un outil agréable d'avoir.
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
class Main
{
public static void main(final String[] argv)
throws NoSuchMethodException,
IllegalAccessException,
IllegalArgumentException,
InvocationTargetException
{
final String methodName;
final Method method;
final Main main;
main = new Main();
if(argv.length == 0)
{
methodName = "foo";
}
else
{
methodName = "bar";
}
method = Main.class.getDeclaredMethod(methodName, int.class);
main.car(method, 42);
}
private void foo(final int x)
{
System.out.println("foo: " + x);
}
private void bar(final int x)
{
System.out.println("bar: " + x);
}
private void car(final Method method,
final int val)
throws IllegalAccessException,
IllegalArgumentException,
InvocationTargetException
{
method.invoke(this, val);
}
}