Как использовать методы интерфейса случайно? - PullRequest
1 голос
/ 13 июня 2011

У меня есть интерфейс и эти методы:

public interface Form {

public void setFirstName (String value);

public void setLastName (String value);

public void setGender (String value);
}

Могу ли я вызвать эти методы случайным образом для объекта? Что-то вроде:

form.randomMethodFromFormInterface(String randomString);

Возможно ли это на самом деле? Просто, чтобы уточнить, я хотел бы заполнить форму случайным образом: иногда просто фамилия, иногда просто имя, иногда только пол.

Ответы [ 8 ]

4 голосов
/ 13 июня 2011
Random rand = new Random();
switch (rand.nextInt(3)) {
  case 0: myForm.setFirstName(myFirstName); break;
  case 1: myForm.setLastName(myLastName); break;
  case 2: myForm.setGender(myGender); break;
  default: throw new IllegalStateException();
}
3 голосов
/ 13 июня 2011

Не могли бы вы использовать Random для выбора 0-2, а затем в зависимости от этого значения вызвать соответствующий метод?

2 голосов
/ 13 июня 2011

Вот общий способ, используя отражение:

private static Random r = new Random();

public static void callRandomMethod(Object target, Class<?> iface, Object ... arguments) {
    List<Method> methods = findFittingMethods(iface, arguments);
    Method m = methods.get(r.nextInt(methods.size()));
    m.invoke(target, arguments);
}
public List<Method> findFittingMethods(Class<?> iface, Object ... arguments
    Method[] allMethods = iface.getMethods();
    List<Method> fittingMethods = new ArrayList<Method>();
    findMethodLoop:
    for(Method candidate : allMethods) {
        Class<?>[] argumentTypes = candidate.getArguments();
        if(argumentTypes.length != arguments.length) {
            continue;
        }
        // check argument types
        for(int i = 0; i < argumentTypes.length; i++) {
           if(arguments[i] == null) {
              if(argumentTypes[i].isPrimitive()) {
                 // null can't be passed to a primitive argument.
                 continue findMethodLoop;
              }
              else {
                 // ... but to every other argument type.
                 continue; // check next argument
              }
           }
           if(argumentTypes[i].isInstance(arguments[i])) {
               continue; // check next argument
           }
           if(argumentTypes[i].isPrimitive()) {
              // hack to check if we have the right wrapper class
              try {
                  Array.set(Array.newInstance(argumentTypes[i], 1), 0, arguments[i]);
                  continue; // check next argument
              }
              catch(ArrayStoreException ex) {
                  continue findMethodLoop;
              }
           }
           // wrong type
           continue findMethodLoop;
        }
        // now we found a method which would accept the arguments, put it into the list.
        fittingMethods.add(candidate);
    }
    return fittingMethods;
}

Конечно, если вы будете делать это часто, вы не будете создавать список методов для каждого вызова, а только один раз и будете использовать его потом. (И если у вас есть только известный интерфейс с небольшим количеством методов, используйте вместо него оператор switch, как рекомендовали другие).

2 голосов
/ 13 июня 2011

Не могли бы вы сделать другой метод в интерфейсе, который генерирует случайное число и вызывает метод на основе этого числа? Хотя я бы поспорил, что есть более простой способ сделать это, чем создать для него интерфейс.

1 голос
/ 13 июня 2011

Могу ли я вызвать эти методы случайным образом для объекта?

Да, это возможно с помощью Reflection.Случайность не реализована в этом примере (я предполагаю, что вы можете легко сделать это со случайным int), и все методы вызываются, не зная, как они называются или сколько методов доступно.Для простоты в примере предполагается, что параметр имеет значение String (как в вашем примере).Конечно, вы должны создать экземпляр класса, который реализует Form:

Class thisClass = Class.forName("FormImpl");
Object o = thisClass.newInstance();

Method[] methods = thisClass.getDeclaredMethods();
for(Method m : methods)
{
  m.invoke(o, "test");
}
1 голос
/ 13 июня 2011

Почему бы не сделать следующий метод:

public static void randomMethodFromFormInterface(Form form, String value) {
    switch(random.nextInt(3) {
        case 0:
            form.setFirstName(value);
            break;
        case 1:
            form.setLastName(value);
            break;
        case 2:
            form.setGenderName(value);
            break;
    }
}

Вы можете поместить его в служебный класс.random здесь, конечно, экземпляр java.util.Random.

1 голос
/ 13 июня 2011

Вы можете разместить различные имена методов в структуре массива.
Затем выберите случайный индекс в области видимости массива.
Затем используйте рефлексию для фактического вызова метода с использованием случайно выбранного имени из предыдущего шага

0 голосов
/ 13 июня 2011

Вы можете сделать что-то вроде ниже. Однако я не уверен, действительно ли мне нравится идея случайного вызова методов в интерфейсе. По-моему, это нарушает контракт и звучит как плохая дизайнерская идея.

import java.util.Random;
public class RandomInterfaceImpl implements RandomInterface {
    private Random rnd;
    public RandomInterfaceImpl(){
        rnd = new Random();
    }
    @Override
    public void setFirstName(String value) {
        System.out.println("called setFirstName");

    }

    @Override
    public void setLastName(String value) {
        System.out.println("called setLastName");

    }

    @Override
    public void setGender(String value) {
        System.out.println("called setGender");

    }

    @Override
    public void getNextRandomMethod(String value) {
        int nextRand = rnd.nextInt(3);
        switch(nextRand){
        case 0: setFirstName(value); break;
        case 1: setLastName(value); break;
        case 2: setGender(value); break;
        }

    }

}

public static void main(String[] args) {
        RandomInterface myInterface = new RandomInterfaceImpl();
        myInterface.getNextRandomMethod("Foo");
        myInterface.getNextRandomMethod("Foo");
        myInterface.getNextRandomMethod("Foo");
    }

печать: -

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