Pregunta

Para mi servidor de juegos Java, envío la ID de acción del paquete que básicamente le dice al servidor para qué sirve el paquete. Quiero mapear cada ID de acción (un entero) a una función. ¿Hay alguna forma de hacer esto sin usar un interruptor?

¿Fue útil?

Solución

¿Y este?

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 necesita pasar algunos argumentos, defina su propia interfaz con una función que tenga un parámetro adecuado y use eso en lugar de ejecutar).

Otros consejos

Java realmente no tiene punteros de funciones (en su lugar obtuvimos clases internas anónimas). Sin embargo, realmente no hay nada de malo en usar un interruptor, siempre y cuando esté activando el valor y no el tipo. ¿Hay alguna razón por la que no quieres usar un interruptor? Parece que tendrá que hacer un mapeo entre ID de acción y acciones en algún lugar de su código, entonces, ¿por qué no mantenerlo simple?

Java no tiene punteros de función de primera clase. Para lograr una funcionalidad similar, debe definir e implementar una interfaz. Puede hacerlo más fácil usando clases internas anónimas, pero todavía no es muy bonita. Aquí hay un ejemplo:

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

¿Alguna vez has usado Swing/AWT? Su jerarquía de eventos resuelve un problema similar. La forma en que Java pasa las funciones es con una interfaz, por ejemplo

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

Entonces, si desea mapear enteros en estos objetos, podría usar algo como un java.util.HashMap<Integer,ActionHandler> para manejar eso. Las implementaciones reales pueden ir en clases anónimas (la mejor aproximación de Java de "lambda") o en las clases adecuadas en algún lugar. Aquí está la forma de clase anónima:

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);

(editar) Si desea ser aún más abusivo, puede inicializar el hashmap así:

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

Sí, pero usar una interfaz significa que debe crear una interfaz para cada devolución de llamada, lo que significa que cada función desea pasar. Crear una clase de delegado para manejar esto le da (no un verdadero puntero de la función), pero la función se pasará y si abusa de un genérico para ser el tipo de retorno, no tiene que lanzar lo que reduce el cuello de botella a casi nada.

El C# Delegate (MulticastDelegate para ser correcto) obtiene la información de usar Method MethodInfo, que es lo mismo que debería hacer para la clase delegada usando java.lang.reflect.method. Publiqué mi código para la clase delegada (t) en otro formulario de este sitio que se ocupa de este problema extacto. Lo hago porque (sí) de C ++ necesito una mejor manera de pasar las funciones (especialmente nulo) y luego tener que crear una interfaz para la función o más. Ahora puedo elegir la función que llena la información del parámetro para ello. ¡Voila! Agradable y utilizable sin perder en velocidad de JIT o JVM. Y si solo tuve la programación de Java solo durante una semana, cualquier programador de Java puede hacerlo.

Además, sirve muy bien al crear un oyente base y una interfaz base para pasar en el oyente. No más tener que escribir otro oyente porque el nombre de la función ha cambiado. Crear una clase delegada tiene grandes ventajas, ya que es muy utilizable y pasable.

Podrías interactuar métodos estáticos. Este método también le permite especificar parámetros. Declare su interfaz ...

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

Y tu mapa ...

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

Luego implementa métodos estáticos que coincidan con la interfaz/parámetros ...

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();
}

Luego puede agregar esos métodos a su mapa ...

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

y llámalos de la siguiente manera ...

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

Otro emprendedor similar podría ser usar proveedores 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();

Puede hacerlo mediante el uso del patrón de la cadena de responsabilidad.

Es un patrón que vincula diferentes objetos juntos como una lista vinculada. es decir, cada objeto tiene una referencia al siguiente en la cadena. Los objetos en la cadena generalmente manejan un comportamiento específico. El flujo entre los objetos es muy similar a la instrucción Case de conmutación.

Hay algunos Gotchas, como que difunde su lógica, una cadena excesivamente larga puede causar problemas de rendimiento. Pero junto con estos Gotchas, tiene el beneficio de una mayor probabilidad y una cohesión más fuerte. Además, no se limita al uso de expresiones de enum, byte, short short y char como el disparador para la ramificación.

Verifique los cierres de cómo se han implementado en la Biblioteca Lambdaj. En realidad tienen un comportamiento muy similar a los delegados de C#:

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

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top