2012-02-17 4 views
3

У меня есть десятки функций, которые являются альтернативами друг другу. Они берут ввод и возвращают выход, но в каждом случае вывод немного отличается. Все они встроены в один класс-оболочку.Динамически вызывающие нестатические методы

Я хочу вызвать их, передав имя метода как строку. Я хотел бы также, чтобы избежать вручную поддерживать огромный список невостребованных если заявления:

if(methodName.equals("method1") 
    return method1(argument); 
... 
else if(methodName.equals("method176") 
    return method176(argument); 

До сих пор я понял, как динамически вызывать методы, но только если методы являются статическими:

try { 
    method = MyMainClass.class.getDeclaredMethod(methodName, MyArgumentClass.class); 
    ResultClass result = (ResultClass)method.invoke(null, myArgument); 
    return result; 
} 
catch(Exception e) 
{ 
    e.printStackTrace(); 
    System.exit(1); 
    return null; 
} 

Возможно ли это для нестатических методов и вызывать функции экземпляров класса вместо статического класса?

+1

не ответ, но: Имейте в виду, что при использовании отражения технически возможно, это, вероятно, не является хорошей идеей. Вы теряете проверку типа компиляции, анализ кода (например, иерархии вызовов в среде IDE) усложняется, и переименование методов требует изменения строк. Я бы посоветовал вам рассмотреть альтернативные методы, такие как шаблон стратегии, или уменьшить количество методов и параметризовать их. – sleske

ответ

4

Да. Используя Java reflection, просто передайте экземпляр, чтобы вызвать его как первый аргумент метода invoke.

Read: http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Method.html#invoke

try { 
    MyArgumentClass argument = new MyArgumentClass(); 
    MyMainClass instance = new MyMainClass(argument); 
    method = MyMainClass.class.getDeclaredMethod(methodName, MyArgumentClass.class); 
    ResultClass result = (ResultClass) method.invoke(instance, myArgument); 
    return result; 
} 
catch(Exception e) 
{ 
    e.printStackTrace(); 
    System.exit(1); 
    return null; 
} 

Как указано в других ответах, это не самый лучший подход к вашей проблеме. Вы должны осуществлять the Strategy pattern так:

interface MyOperation{ 
    public ResultClass execute(MyArgumentClass argument); 
} 

public class Method1 implements MyOperation { 
    public ResultClass execute(MyArgumentClass argument){ 
     .... 
    } 
} 

public class Method176 implements MyOperation { 
    public ResultClass execute(MyArgumentClass argument){ 
     .... 
    } 
} 

public class DoIt{ 
    public ResultClass doIt(MyOperation method, MyArgumentClass argument){ 
     return method.doIt(argument); 
    } 
} 
+0

Спасибо, вот что я искал. – Marek

5

Если возможно, лучше избегайте отражения. Похоже, ваша проблема может быть решена с лучшей конструкцией, используя Strategy pattern.

+0

+1 При использовании отражения технически возможно, это, вероятно, не очень хорошая идея. – sleske

+0

Основываясь на примере Википедии, это, похоже, не сильно изменилось. Поскольку я хочу перейти в «стратегию» как аргумент String, я все же получаю огромный список операторов if: if (strategy.equals («add»)) context = new Context (новый ConcreteStrategyAdd()); if (strategy.equals ("subtract")) context = new Контекст (новый ConcreteStrategySubtract()); ... – Marek

+0

Для этого вы можете использовать карту . –

1

Да, это возможно. Передайте объект, который вы хотите вызвать метод, в качестве первого аргумента для вызова invoke. Вызовите getClass на объект, чтобы получить класс для использования.

1

Получите экземпляр своего метода, который извлекается из класса, как вы делаете, затем вызывайте Method.invoke() с экземпляром класса, на который вы хотите вызвать метод.

Вы также можете использовать некоторые из бобов, доступных от Spring, чтобы выполнить что-то подобное, если вам интересно идти по этому маршруту.

Смежные вопросы