Pergunta

Para o meu servidor de jogo Java, envio o ID de ação do pacote, que basicamente informa ao servidor para que serve o pacote. Eu quero mapear cada ID de ação (um número inteiro) para uma função. Existe uma maneira de fazer isso sem usar um switch?

Foi útil?

Solução

Que tal 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();

(Se você precisar passar alguns argumentos, defina sua própria interface com uma função com um parâmetro adequado e use -o em vez de executável).

Outras dicas

Java realmente não tem ponteiros de função (temos aulas internas anônimas). No entanto, não há realmente nada de errado em usar um switch, desde que você esteja ligando o valor e não no tipo. Existe algum motivo pelo qual você não deseja usar um switch? Parece que você terá que fazer um mapeamento entre IDs de ação e ações em algum lugar do seu código, então por que não mantê -lo simples?

O Java não possui ponteiros de função de primeira classe. Para obter funcionalidade semelhante, você deve definir e implementar uma interface. Você pode facilitar o uso de classes internas anônimas, mas ainda não é muito bonito. Aqui está um exemplo:

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

Você já usou swing/awt? Sua hierarquia de eventos resolve um problema semelhante. A maneira como Java passa as funções é com uma interface, por exemplo

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

Então, se você quiser mapear números inteiros nesses objetos, você pode usar algo como um java.util.HashMap<Integer,ActionHandler> para gerenciar isso. As implementações reais podem ir em aulas anônimas (a melhor aproximação de Java de "lambda") ou em classes adequadas em algum lugar. Aqui está a maneira da classe 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) Se você quiser ser ainda mais abusivo, pode inicializar o hashmap assim:

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

Sim, mas usar uma interface significa que você precisa criar uma interface para cada retorno de chamada, o que significa que todas as funções que você deseja passar. Criar uma classe delegada para lidar com isso fornece a você (não um ponteiro de função verdadeiro), mas a função a ser passada e, se você abusar de um genérico para ser o tipo de retorno, não precisa lançar o que corta o gargalo para quase nada.

O delegado C# (multicastDelegate para estar correto) obtém as informações do uso do método MethodInfo, que é a mesma coisa que você precisaria fazer para a classe Delegate usando java.lang.reflect.method. Publiquei meu código para a classe Delegate (T) em outra forma deste site que lida com esta questão de extrema. Eu faço porque (sim) sendo de C ++ eu preciso de uma maneira melhor de passar as funções (especialmente vazias) e depois criar uma interface para a função ou mais. Agora eu posso escolher o preenchimento de funções nas informações de parâmetro para ela. Voila`! Nice e utilizável, sem perda perceptível em velocidade de JIT ou JVM. E se eu fiz apenas aprender a programação Java por apenas uma semana, qualquer programador Java pode fazê -lo.

Além disso, serve muito bem ao criar um ouvinte base e uma interface básica para passar no ouvinte. Não há mais que escrever outro ouvinte porque o nome da função mudou. Criar uma aula de delegado tem grandes vantagens, como é muito utilizável e aceitável.

Você pode interface os métodos estáticos. Este método também permite especificar parâmetros. Declare sua interface ...

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

E seu mapa ...

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

Em seguida, implemente métodos estáticos que correspondam à interface/params ...

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

Você pode adicionar esses métodos ao seu mapa ...

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

e ligue para eles o seguinte ...

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

Outra abordagem semelhante pode ser usar os fornecedores do 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();

You can do this through the use of the chain of responsibility pattern.

It is a pattern that links different objects to together kind of like a linked list. i.e. Each object has a reference to next in the chain. The objects in the chain usually handles one specific behavior. The flow between the objects is very similar to the switch-case statement.

There are some gotchas, such as, it spreads your logic out, an excessively long chain can cause performance problems. But along with these gotchas you have the benefit of increased testability, and stronger cohesion. Also you are not limited to the using enum, byte, int short, and char expressions as the trigger for branching.

Check the closures how they have been implemented in the lambdaj library. They actually have a behavior very similar to C# delegates:

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

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top