2009-06-01 13 views
7

en Python, si tengo unas pocas funciones que me gustaría llamar basado en una entrada, puedo hacer esto:Java equivalente de correlación de funciones en Python

lookup = {'function1':function1, 'function2':function2, 'function3':function3} 
lookup[input]() 

Es decir que tengo un diccionario de la función nombre asignado a la función, y llamar a la función mediante una búsqueda de diccionario.

¿Cómo hacer esto en Java?

Respuesta

3

Hay varias maneras de abordar este problema. La mayoría de estos fueron ya publicados:

  • Commands - llevar un montón de objetos que tienen un execute() o invocar() en un mapa; busca el comando por nombre, luego invoca el método.
  • Polymorphism - Más en general que los comandos, puede invocar métodos en cualquier conjunto relacionado de objetos.
  • Finalmente hay reflexión: puede usar la reflexión para obtener referencias a los objetos java.lang.Method. Para un conjunto de clases/métodos conocidos, esto funciona bastante bien y no hay demasiada sobrecarga una vez que carga los objetos del Método. Puede usar esto para, por ejemplo, permitir que un usuario escriba código Java en una línea de comando, que ejecuta en tiempo real.

Personalmente, utilizaría el enfoque Comando. Los comandos se combinan bien con Template Methods, lo que le permite aplicar ciertos patrones en todos sus objetos de comando. Ejemplo:

public abstract class Command { 
    public final Object execute(Map<String, Object> args) { 
    // do permission checking here or transaction management 
    Object retval = doExecute(args); 
    // do logging, cleanup, caching, etc here 
    return retval; 
    } 
    // subclasses override this to do the real work 
    protected abstract Object doExecute(Map<String, Object> args); 
} 

Me recurrir a la reflexión sólo cuando es necesario utilizar este tipo de mapeo de clases cuyo diseño no se controla, y para el cual no es práctico para hacer comandos. Por ejemplo, no podría exponer la API de Java en un comando-shell haciendo comandos para cada método.

2

Puede utilizar un Map < String, Method> o Map < String, Llamable> etc, y luego usar map.get ("function1"). Invoke (...). Pero generalmente este tipo de problemas se abordan de forma más limpia mediante el uso de polimorfismo en lugar de una búsqueda.

+1

Específicamente suena como el patrón Estrategia (http://en.wikipedia.org/wiki/Strategy_pattern#Java) podría ayudar aquí (no tan corto como el equivalente de Python, pero ...). – Gadi

+0

¿Cómo hacer esto por polimorfismo? La función que se debe involucrar se basa en la información del cliente. ¿Podrías mostrarme? Gracias. – Ross

14

Java no tiene métodos de primera clase, por lo que el command pattern es su amigo ...

Disclamer: código no probado!

public interface Command 
{ 
    void invoke(); 
} 

Map<String, Command> commands = new HashMap<String, Command>(); 
commands.put("function1", new Command() 
{ 
    public void invoke() { System.out.println("hello world"); } 
}); 

commands.get("function1").invoke(); 
+5

Java tiene cierres, pero no métodos de primera clase. Una clase interna anónima cierra las variables (finales) en su ámbito circundante. – Nat

+0

@Nat - en realidad, nunca había pensado en clases anónimas o internas como cierres, pero supongo que sí. Respuesta actualizada para eliminar ese comentario. ¡Gracias! –

1

ejemplo polimórfica ..

public interface Animal {public void speak();}; 
public class Dog implements Animal {public void speak(){System.out.println("treat? treat? treat?");}} 
public class Cat implements Animal {public void speak(){System.out.println("leave me alone");}} 
public class Hamster implements Animal {public void speak(){System.out.println("I run, run, run, but never get anywhere");}} 

Map<String,Animal> animals = new HashMap<String,Animal>(); 
animals.put("dog",new Dog()); 
animals.put("cat",new Cat()); 
animals.put("hamster",new Hamster()); 
for(Animal animal : animals){animal.speak();} 
0

Como se mencionó en otras preguntas, un Map<String,MyCommandType> con clases internas anónimas es una forma verídica de hacerlo.

Una variación consiste en utilizar enumeraciones en lugar de las clases internas anónimas. Cada constante de la enumeración puede implementar/anular los métodos de la interfaz enumerada o implementada, al igual que la técnica de clase interna anónima pero con un poco menos de desorden. Creo que Effective Java 2nd Ed trata de cómo inicializar un mapa de enums. Para mapear desde el nombre enum simplemente requiere llamar al MyEnumType.valueOf(name).

0

Desafortunadamente, Java no tiene funciones de primera clase, pero tenga en cuenta la siguiente interfaz:

public interface F<A, B> { 
    public B f(A a); 
} 

un modelo del tipo para funciones de tipo A Para escribir B, como valores de primera clase que puede pasar alrededor. Lo que quiere es un Map<String, F<A, B>>.

Functional Java es una biblioteca bastante completa centrada en funciones de primera clase.

0

Como todos dijeron, Java no admite funciones como objetos de primer nivel. Para lograr esto, usa un Functor, que es una clase que envuelve una función. Steve Yegge tiene un nice rant sobre eso.

Para ayudarle con esta limitación, la gente escribe bibliotecas functor: jga, Commons Functor