Java-эквивалент отображения функций в Python - PullRequest
9 голосов
/ 01 июня 2009

В Python, если у меня есть несколько функций, которые я хотел бы вызвать на основе ввода, я могу сделать это:

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

То есть у меня есть словарь имени функции, сопоставленный с функцией, и вызов функции с помощью поиска в словаре.

Как это сделать в Java?

Ответы [ 7 ]

15 голосов
/ 01 июня 2009

В Java нет первоклассных методов, поэтому шаблон команды - ваш друг ...

Disclamer: код не проверен!

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();
4 голосов
/ 01 июня 2009

Есть несколько способов решения этой проблемы. Большинство из них уже опубликовано:

  • Команды - Хранить на карте несколько объектов, у которых есть метод execute () или invoke (); найдите команду по имени, затем вызовите метод.
  • Полиморфизм - В более широком смысле, чем команды, вы можете вызывать методы для любого связанного набора объектов.
  • Наконец, есть отражение - вы можете использовать отражение, чтобы получить ссылки на объекты java.lang.Method. Для набора известных классов / методов это работает довольно хорошо, и при загрузке объектов Method не возникает слишком много накладных расходов. Вы можете использовать это, например, чтобы позволить пользователю вводить код Java в командную строку, которую вы выполняете в реальном времени.

Лично я бы использовал командный подход. Команды хорошо сочетаются с Методы шаблонов , что позволяет вам применять определенные шаблоны для всех ваших объектов команд. Пример:

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

Я бы прибегнул к рефлексии только тогда, когда вам нужно использовать этот вид отображения для классов, дизайн которых вы не контролируете, и для которых нецелесообразно создавать команды. Например, вы не можете представить Java API в командной оболочке, выполнив команды для каждого метода.

2 голосов
/ 01 июня 2009

Вы можете использовать Map или Map и т. Д., А затем использовать map.get ("function1"). Invoke (...). Но обычно такого рода проблемы решаются более чисто с помощью полиморфизма вместо поиска.

1 голос
/ 01 июня 2009

К сожалению, Java не имеет функций первого класса, но рассмотрим следующий интерфейс:

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

Этот тип моделирует функции от типа A до типа B как первоклассные значения, которые вы можете передавать. То, что вы хотите, это Map<String, F<A, B>>.

Функциональная Java - довольно полная библиотека, сосредоточенная вокруг первоклассных функций.

1 голос
/ 01 июня 2009

Полиморфный пример ..

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 голосов
/ 01 июня 2009

Как и все остальные, Java не поддерживает функции в качестве объектов первого уровня. Чтобы достичь этого, вы используете Functor, который является классом, который упаковывает функцию. У Стива Йегге есть хорошая напыщенная речь об этом.

Чтобы помочь вам с этим ограничением, люди пишут библиотеки функторов: jga , Commons Functor

0 голосов
/ 01 июня 2009

Как уже упоминалось в других вопросах, Map<String,MyCommandType> с анонимными внутренними классами - это один многословный способ сделать это.

Разновидностью является использование перечислений вместо анонимных внутренних классов. Каждая константа перечисления может реализовывать / переопределять методы перечисления или реализованного интерфейса, почти так же, как метод анонимного внутреннего класса, но с меньшим количеством беспорядка. Я считаю, что Effective Java 2nd Ed имеет дело с тем, как инициализировать карту перечислений. Для сопоставления с именем перечисления просто требуется позвонить MyEnumType.valueOf(name).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...