Ответ 1
Последнее решение, которое я использую в настоящее время, - это определение иерархии интерфейсов (как указано в вопросе) и использование методов по умолчанию, чтобы избежать сбоя. Псевдо код выглядит следующим образом:
interface VarArgsRunnable {
default void run(Object ... arguments) {
throw new UnsupportedOperationException("not possible");
}
default int getNumberOfArguments() {
throw new UnsupportedOperationException("unknown");
}
}
и интерфейс для четырех аргументов, например:
@FunctionalInterface
interface VarArgsRunnable4 extends VarArgsRunnable {
@Override
default void run(Object ... arguments) {
assert(arguments.length == 4);
run(arguments[0], arguments[1], arguments[2], arguments[3]);
}
void run(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4);
@Override
default int getNumberOfArguments() {
return 4;
}
}
Определив 11 интерфейсов от VarArgsRunnable0 до VarArgsRunnable10, перегрузка метода становится довольно простой.
public void myMethod(VarArgsRunnable runnable, Object ... arguments) {
runnable.run(arguments);
}
Так как Java не может составить Лямбду, найдя правильный расширенный функциональный интерфейс VarArgsRunnable, используя что-то вроде instance.myMethod((index, value) -> doSomething(to(index), to(value)), 10, "value")
, нужно перегрузить метод, используя правильный интерфейс.
public void myMethod(VarArgsRunnable2 runnable, Object arg0, Object arg1) {
myMethod((VarArgsRunnable)runnable, combine(arg0, arg1));
}
private static Object [] combine(Object ... values) {
return values;
}
Так как для этого требуется, чтобы объект Object был привязан к любому присвоенному типу, используя to(...)
, можно использовать параметризацию с помощью Generics, чтобы избежать этого использования.
Метод to
выглядит следующим образом: public static T to (значение объекта) { return (T);//Подавить это предупреждение }
Пример является хромым, но я использую его для вызова метода с несколькими аргументами, являющегося перестановкой всех потенциальных комбинаций (для целей тестирования), таких как:
run((index, value) -> doTheTestSequence(index, value), values(10, 11, 12), values("A", "B", "C"));
Итак, эта маленькая строка запускает 6 вызовов. Таким образом, вы видите, что это аккуратный помощник, способный тестировать несколько элементов в одной строке, вместо того, чтобы определять намного больше или использовать несколько методов в TestNG и любом...
PS: Не нужно использовать отражения, это очень хорошо, так как он не может потерпеть неудачу и, скорее всего, сохранит аргумент count wise.