Как реализовать метод Java, который будет вызывать другой метод, основанный на имени вызывающего класса? - PullRequest
0 голосов
/ 17 января 2019

У нас есть класс Java, WebCenterGrid. Этот класс полон методов для работы в сетке, таких как поиск строки, поиск значения ячейки, сортировка столбца. У нас есть несколько классов, которые используют этот класс. Все классы, использующие его, ссылаются на разные таблицы, но функциональность одинакова.

Единственное, что отличается, это как создать сетку. Некоторые классы выполняют поиск, который заполняет сетку (поиск также обновляется). Некоторые делают updateList () для обновления сетки и т. Д.

Я бы хотел добавить метод в WebCenterGrid для обновления сетки. Проблема в том, что, как я сказал, каждый метод имеет свое имя.

Я как-то хочу передать в WebCenterGrid имя метода, вызываемого для обновления. Я провел некоторые поиски и нашел кое-что о лямбде, которое я не совсем понял.

Я давно не использовал C ++, но был какой-то способ передать метод в эти методы. Этот класс в Java не C ++, но есть ли какой-то понятный эквивалент?

 public class WebCenterGrid {
    ....
    ....
    public void refresh(Method meth) {
           meth();
    }
 }

Ответы [ 3 ]

0 голосов
/ 17 января 2019

Ну, так как мы не можем увидеть ваш код, я предложу следующее решение, основанное на моем личном предположении о том, как работает ваш код.

Имейте в виду, что этот метод не так масштабируем и довольно неэффективен, если у вас есть 100 различных способов создания сеток.

Однако, если у вас есть (например, 3) типы таких способов, например, вы можете использовать константы!

См. Ниже:

 public class WebCenterGrid {
    //Declare constants with meaningful names for grid creation (add more as you like)
    public static final int DEEP_COPY=1, SEARCH=2, REBUILD=3;

    public void makeDeepCopy(){
    //implementation goes here..
    }

    public void searchAndPopulate(){
    //implementation goes here..
    }

    public void rebuildGrid(){
    //implementation goes here..
    }

    public void refresh(int operation) {
        switch(operation) {
        //based on 'operation', call appropriate method!
        case DEEP_COPY: this.makeDeepCopy(); break;
        case SEARCH: this.searchAndPopulate(); break;
        case REBUILD: this.rebuildGrid(); break;
        //you can have a default operation for any parameter that is not
        //in the list of our defined constants(i.e. the number 143)
        default: simpleRefresh(); break;
        }
    }
 }

Так, что заставляет работать вышеупомянутое решение?

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

ПРИМЕР (Допустим, AwesomeGridCreator - это класс, который при вызове refresh () для обновления сетки должен выполнить поиск и затем заполнить сетку (, как вы упомяните в своем вопросе ).

Мы называем целое число (для простоты) SEARCH_POPULATE, и мы даем ему ЛЮБОЕ значение, которое мы хотим. Например 286.

Затем мы можем использовать эту константу из любого другого класса, потому что нас не волнует, каково ее значение (в данном случае 286, но функциональность, которую она предоставляет при вызове refresh().

public class WebCenterGrid {
    /*some code here*/
    public static final int SEARCH_POPULATE = 286; //integer value doesn't matter

    public void refresh(int operation) {
        switch(operation) {
        case SEARCH_POPULATE: this.searchAndPopulate(); break;
    }


    /*...some other code here, we don't care..*/
}

Затем, в классе «вызова»:

public class AwesomeGridCreator{
  //some code here

  WebCenterGrid wcg = new WebCenterGrid();
  //The parameter that we pass below (2), will make the refresh() method call
  //the method that we defined in our switch cases ('searchAndPopulate()').
  wcg.refresh(wcg.SEARCH_POPULATE);
}
0 голосов
/ 17 января 2019

Вместо параметра Method примите Interface, и реализация определит, что будет вызываться.

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

Пример:

public class Main {

    public static void main(String[] args) {
        act(new Run());
        act(new Swim());
        // Passing a body of the function you want to execute
        act(() -> System.out.println("walking"));
    }

    public static void act(Action action) {
        action.act();
    }
}

@FunctionalInterface
interface Action {
    void act();
}

class Run implements Action {
    @Override
    public void act() {
        System.out.println("running");
    }
}

class Swim implements Action {
    @Override
    public void act() {
        System.out.println("swimming");
    }
}

Выход:

running
swimming
walking

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

public class Main {

    static Map<ActionType, Action> actionResolver = new HashMap<>();

    // Static init is just for brevity sake
    static {
        actionResolver.put(ActionType.RUN, new Run());
        actionResolver.put(ActionType.WALK, new Walk());
        actionResolver.put(ActionType.SWIM, new Swim());
    }

    public static void main(String[] args) {
        act(ActionType.RUN);
        act(ActionType.WALK);
        act(ActionType.SWIM);
    }

    public static void act(ActionType actionType) {
        Action action = actionResolver.get(actionType);
        if (action == null)
            throw new IllegalArgumentException("ActionType was not registered");

        action.act();
    }
}

enum ActionType {
    RUN,
    SWIM,
    WALK
}

Вывод такой же, как указано выше.

0 голосов
/ 17 января 2019

В принципе, есть два способа.

Один из них - использовать отражение , это означает: полагаться на информацию типа runtime , обычно полученную из необработанных строк. Как сказать: у меня есть некоторый объект класса X, и я хочу вызвать метод с именем "doTheFoo ()" для этого объекта.

См. здесь для всех деталей славы.

Немного лучше - использовать класс MethodHandle вместо класса "сырого" метода отражения. См. здесь для ручек.

Но тогда: отражение происходит во время выполнения. Ваш код компилируется нормально, но если вы ошибаетесь в деталях, он взрывается во время выполнения.

Таким образом, я предлагаю рассмотреть лямбды, основанные на Функция , см. здесь .

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