Определение функции обратного вызова для заданного значения - PullRequest
0 голосов
/ 13 сентября 2010

Можно ли в Java связать некоторый объект (например, строку) с вызываемой функцией?

У меня есть два похожих меню, и у обоих есть onClickListener с некоторым кодом, подобным этому:

if (item.id==0) {
 doSomeFunction(argument);
}
else if (item.id==1) {
 doSomeOtherFunction();
}
else if (item.id==2) {
 doStuff(arg2);
}
else {

}

Я просто хотел бы иметь объект (т.е. Hashtable), который позволил бы мне определять ассоциации между "item.id" -> "кодом для выполнения".

Пример:

0 -> doSomeFunction(argument);
1 -> doSomeOtherFunction();
2 -> doStuff(arg2);

В результате я мог пропустить эти условные выражения и просто выполнить вызов функции, сохраненной для данного item.id.

Например, с Лисп я мог бы связать item.id с функцией, а затем использовать "funcall" Лисп для вызова этой функции.

Есть ли стандартный способ сделать что-то подобное в Java?

Существуют ли альтернативные решения для пропуска условных выражений?

Обратите внимание, что вызываемым функциям может потребоваться получить параметры.

Спасибо.

Ответы [ 4 ]

3 голосов
/ 13 сентября 2010

Так как похоже, что вашим функциям не нужно возвращать какие-либо значения, вы можете связать каждый ключ ID с Runnable объектом, который вызывает нужный метод.Например:

Map<Integer, Runnable> map = ...;
map.put(0, new Runnable() {
  public void run() {
    doSomeFunction();
  }
});

map.get(0).run();

Если вам нужны методы, чтобы иметь возможность вернуть значение, вы можете использовать Callable вместо Runnable.Вы также можете создать свой собственный подобный интерфейс и использовать его вместо этого, если это необходимо.

В настоящее время в Java подобные вещи должны выполняться с экземпляром класса с помощью одного абстрактного метода, такого как Runnable.Java 7 или 8 (в зависимости от того, как они решат действовать) добавят лямбда-выражения и ссылки на методы, что, я думаю, именно то, что вам действительно нужно.Ссылки на методы позволят вам сделать что-то подобное (используя Map<Integer, Runnable>, как указано выше).

map.put(0, Foo#doSomeFunction());

Редактировать :

Ваше обновление указывает, что некоторые изэти методы должны иметь аргументы, передаваемые им.Тем не менее, вы, кажется, просите две разные вещи.В вашем примере объявления сопоставления

0 -> doSomeFunction(argument);
1 -> doSomeOtherFunction();
2 -> doStuff(arg2);

указаны аргументы, указывающие на то, что это либо значения, доступные на момент объявления объявления сопоставления, либо поля в классе или что-то подобное.В любом случае вы сможете объявить их при создании Runnable:

 new Runnable() {
   public void run() {
     doSomeFunction(argument);
   }
 }

Здесь argument должно быть либо полем, либо объявлено final.

Если, с другой стороны, у вас нет ссылок на аргументы в то время, когда вы создаете отображение, вам придется создать некоторый непротиворечивый интерфейс, которым могли бы поделиться все вызовы метода.Например, наименее распространенным интерфейсом, который мог бы работать для вашего образца, был бы тот, который объявлял два параметра и возвращал void:

public interface CustomRunnable<T,G> {
  public void run(T arg1, G arg2);
}

Тогда вы могли бы иметь:

map.put(0, new CustomRunnable<Foo,Bar>() {
  public void run(Foo arg1, Bar arg2) {
    doSomeFunction(arg1);
  }
});
map.put(1, new CustomRunnable<Foo,Bar>() {
  public void run(Foo arg1, Bar arg2) {
    doSomeOtherFunction();
  }
});
map.put(2, new CustomRunnable<Foo,Bar>() {
  public void run(Foo arg1, Bar arg2) {
    doStuff(arg2);
  }
});

Каждый CustomRunnable использует только те аргументы, которые ему нужны, если таковые имеются.Тогда вы могли бы сделать звонок следующим образом:

map.get(item.id).run(argument, arg2);

Очевидно, это становится довольно уродливым, но это в значительной степени то, что вам нужно сделать в этом случае.

1 голос
/ 13 сентября 2010

Обычная вещь, которую нужно сделать, это добавить разные слушатели действий (команды) для каждого пункта меню, реализованные в виде короткого анонимного внутреннего класса. К сожалению, синтаксис в настоящее время многословен и не помогает запускать время, но в целом это лучший подход.

Вы не говорите, какую библиотеку вы используете. onClickListener не Swing, но если бы вы использовали Swing, вы бы хотели JMenuItem.addActionListener.

1 голос
/ 13 сентября 2010

Да, есть несколько способов сделать это.Одним из примеров является анонимная реализация интерфейса и его сохранение в HashMap, что-то вроде этого:

public class MyListeningClass
{
    ...

    public interface MyEventHandler
    {
        public void handle(String myParam);
    }

    private HashMap<ItemType, MyEventHandler>  eventHandlers= new HashMap<ItemType, MyEventHandler>();

    initItems()
    {
        //do for each item
        eventHandlers.put(item1, new MyEventHandler(){public void handle(String myParam){
                   //do whatever I want to
                 }});
    }

    myListeningMethod(ItemType item)
    {
        eventHandlers.get(item).handle("a parameter");
    }
}
0 голосов
/ 13 сентября 2010

Java Swing для ответа на этот вопрос является класс действий. в основном это соответствует шаблону команды ...

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