Question

Pour mon serveur de jeu Java, j'envoie l'ID d'action du paquet qui indique essentiellement au serveur à quoi sert le paquet. Je veux cartographier chaque ID d'action (un entier) à une fonction. Existe-t-il un moyen de le faire sans utiliser de commutateur?

Était-ce utile?

La solution

Et celui-ci?

HashMap<Integer, Runnable> map = new HashMap<Integer, Runnable>();
map.put(Register.ID, new Runnable() { 
    public void run() { functionA(); }
});
map.put(NotifyMessage.ID, new Runnable() { 
    public void run() { functionB(); }
});
// ...
map.get(id).run();

(Si vous avez besoin de transmettre certains arguments, définissez votre propre interface avec une fonction ayant un paramètre approprié et utilisez-le au lieu de runnable).

Autres conseils

Java n'a pas vraiment de pointeurs de fonction (nous avons plutôt des classes intérieures anonymes). Cependant, il n'y a vraiment rien de mal à utiliser un commutateur, tant que vous allumez la valeur et non sur le type. Y a-t-il une raison pour laquelle vous ne voulez pas utiliser un commutateur? Il semble que vous devrez faire un mappage entre les identifiants d'action et les actions quelque part dans votre code, alors pourquoi ne pas rester simple?

Java n'a pas de pointeurs de fonction de première classe. Afin d'obtenir des fonctionnalités similaires, vous devez définir et implémenter une interface. Vous pouvez faciliter l'utilisation de classes intérieures anonymes, mais ce n'est toujours pas très joli. Voici un exemple:

public interface PacketProcessor
{
    public void processPacket(Packet packet);
}

...

PacketProcessor doThing1 = new PacketProcessor()
{
    public void processPacket(Packet packet)
    {
        // do thing 1
    }
};
// etc.

// Now doThing1, doThing2 can be used like function pointers for a function taking a
// Packet and returning void

Avez-vous déjà utilisé Swing / AWT? Leur hiérarchie d'événements résout un problème similaire. La façon dont Java passe les fonctions est avec une interface, par exemple

public interface ActionHandler {
    public void actionPerformed(ActionArgs e);
}

Ensuite, si vous souhaitez cartographier les entiers sur ces objets, vous pouvez utiliser quelque chose comme un java.util.HashMap<Integer,ActionHandler> pour gérer cela. Les implémentations réelles peuvent soit suivre dans des classes anonymes (la meilleure approximation de Java de "Lambda") ou dans les classes appropriées quelque part. Voici la voie des cours anonymes:

HashMap<Integer,ActionHandler> handlers;
handlers.put(ACTION_FROB, new ActionHandler() {
    public void actionPerformed(ActionArgs e) {
        // Do stuff
        // Note that any outer variables you intend to close over must be final.
    }
});
handlers.get(ACTION_FROB).actionPerformed(foo);

(éditer) Si vous voulez être encore plus abusif, vous pouvez initialiser le hashmap comme ça:

HashMap<Integer,String> m = new HashMap<Integer,String>() {{
    put(0,"hello");
    put(1,"world");
}};

Oui, mais à l'aide d'une interface signifie que vous devez créer une interface pour chaque rappel, ce qui signifie chaque fonction que vous souhaitez passer. La création d'une classe de délégué pour gérer cela vous donne (pas un véritable pointeur de fonction) mais la fonction à passer et si vous abusez d'un générique pour être le type de retour, vous n'avez pas à lancer ce qui coupe le goulot d'étranglement à presque rien.

Le délégué C # (MultiCastDelegate pour être correct) obtient les informations de l'utilisation de la méthode Méthode qui est la même chose que vous devez faire pour la classe de délégué à l'aide de java.lang.reflect.method. J'ai publié mon code pour la classe du délégué (T) sur une autre forme de ce site traitant de ce problème d'extact. Je le fais parce que (oui) étant de C ++, j'ai besoin d'un meilleur moyen de passer des fonctions (en particulier void) puis d'avoir à créer une interface pour la fonction ou plus. Maintenant, je peux choisir la fonction remplissant les informations des paramètres. Voila`! Nice et utilisable sans perte notable de vitesse de Jit ou JVM. Et si je n'ai appris que la programmation Java pendant une semaine seulement, tout programmeur Java peut le faire.

En outre, il sert très bien lors de la création d'un auditeur de base et d'une interface de base à passer dans l'auditeur. Plus besoin d'écrire un autre auditeur parce que le nom de la fonction a changé. La création d'une classe de délégués présente de grands avantages, comme cela est très utilisable et passable.

Vous pouvez interfacer des méthodes statiques. Cette méthode vous permet également de spécifier des paramètres. Déclarez votre interface ...

public interface RouteHandler {
    void handleRequest(HttpExchange t) throws IOException;
}

Et votre carte ...

private Map<String, RouteHandler> routes = new HashMap<>();

Implémentez ensuite les méthodes statiques qui correspondent à l'interface / paramètres ...

public static void notFound(HttpExchange t) throws IOException {
    String response = "Not Found";

    t.sendResponseHeaders(404, response.length());
    OutputStream os = t.getResponseBody();
    os.write(response.getBytes());
    os.close();
}

Vous pouvez ensuite ajouter ces méthodes dans votre carte ...

routes.put("/foo", CoreRoutes::notFound);

Et appelez-les comme suit ...

RouteHandler handler = routes.get("/foo");
handler.handleRequest(exchange);

Un autre aperçu similaire pourrait être d'utiliser les fournisseurs de Java 8:

Map<Integer, Supplier<T> suppliers = new HashMap();
suppliers.put(1, () -> methodOne());
suppliers.put(2, () -> methodTwo());

// ...

public T methodOne() { ... }
public T methodTwo() { ... }

// ...

T obj = suppliers.get(id).run();

Vous pouvez le faire grâce à l'utilisation du modèle de la chaîne de responsabilité.

C'est un modèle qui relie différents objets à ensemble comme une liste liée. c'est-à-dire que chaque objet a une référence à Suivant dans la chaîne. Les objets de la chaîne gère généralement un comportement spécifique. Le flux entre les objets est très similaire à l'instruction de cas de commutateur.

Il y a des gotchas, tels que, il étend votre logique, une chaîne excessivement longue peut causer des problèmes de performance. Mais avec ces gotchas, vous avez l'avantage d'une testabilité accrue et d'une cohésion plus forte. Vous n'êtes pas non plus limité à l'utilisation des expressions d'énumération, d'octet, int courtes et de char comme déclencheur de la ramification.

Vérifiez les fermetures comment elles ont été mises en œuvre dans la bibliothèque Lambdaj. Ils ont en fait un comportement très similaire aux délégués C #:

http://code.google.com/p/lambdaj/wiki/closures

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top