Четыре способа написания обратного вызова Java (отражение, прямой вызов, вызов интерфейса, лямбда-выражение)

Java
Четыре способа написания обратного вызова Java (отражение, прямой вызов, вызов интерфейса, лямбда-выражение)

1. Введение

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

Выше приведено определение «функции обратного вызова» из Википедии. Для обратных вызовов разные языки имеют разные формы обратных вызовов, например:

  • C, C++ позволяют передавать указатели на функции в качестве параметров;
  • JavaScript, Python позволяют передавать имена функций в качестве параметров.

В этой статье будут представлены четыре способа написания обратных вызовов на Java:

  • отражение;
  • позвонить напрямую;
  • вызов интерфейса;
  • Лямбда-выражения.

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

2. Отражение

Механизм отражения Java позволяет нам получать информацию о классе, включая его методы. Мы получим функцию обратного вызова типа Method и передадим ее в функцию запроса. Пример выглядит следующим образом:

Метод send в классе Request имеет два параметра, clazz и method, которые являются типом класса и типом метода соответственно. Параметр метода здесь — это функция обратного вызова, которая должна быть передана. экземпляр необходим, поэтому объект класса класса, в котором находится функция обратного вызова, передается в качестве параметра, и объект создается через newInstance, который будет успешно вызван через вызов отражения.

public class Request{
    public void send(Class clazz, Method method) throws Exception {
        // 模拟等待响应
        Thread.sleep(3000);
        System.out.println("[Request]:收到响应");
        method.invoke(clazz.newInstance());
    }
}

Класс CallBack очень прост и содержит только один метод processResponse, который используется в качестве функции обратного вызова для обработки ответа.

public class CallBack {
    public void processResponse() {
        System.out.println("[CallBack]:处理响应");
    }
}

В основном методе мы создаем новый поток для отправки запроса и передаем в него необходимые методы CallBack.class и processResponse.

public class Main {
    public static void main(String[] args) throws Exception {
        Request request = new Request();
        System.out.println("[Main]:我开个线程去异步发请求");
        new Thread(() -> {
            try {
                request.send(CallBack.class, CallBack.class.getMethod("processResponse"));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }).start();
        System.out.println("[Main]:请求发完了,我去干点别的");
        Thread.sleep(100000);
    }
}
/** Output:
[Main]:我开个线程去异步发请求
[Main]:请求发完了,我去干点别的
[Request]:收到响应
[CallBack]:处理响应
*/

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

3. Прямой звонок

Перепишем параметр метода send в параметр типа CallBack. следующее:

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

public class Request{
    public void send(CallBack callBack) throws Exception {
        // 模拟等待响应
        Thread.sleep(3000);
        System.out.println("[Request]:收到响应");
        callBack.processResponse();
    }
}

В основной функции мы создаем новый объект CallBack в качестве параметра метода отправки.

public class Main {
    public static void main(String[] args) throws Exception {
        Request request = new Request();
        System.out.println("[Main]:我开个线程去异步发请求");
        CallBack callBack = new CallBack();
        new Thread(() -> {
            try {
                request.send(callBack);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }).start();
        System.out.println("[Main]:请求发完了,我去干点别的");
        Thread.sleep(100000);
    }
}

Эта реализация очень проста, но проблема в том, что она не соответствует принципу замыкания модификации. То есть, когда мы хотим изменить метод «обработки ответа», нам придется модифицировать метод processRequest() класса CallBack. И если мы изменим класс CallBack на интерфейс, мы можем просто заменить реализацию CallBack. Ниже показано, как написать интерфейсный вызов.

4. Вызов интерфейса

Сначала измените класс CallBack на интерфейс.

public interface CallBack {
    public void processResponse();
}

Добавьте еще один класс реализации CallBackImpl интерфейса CallBack.

public class CallBackImpl implements CallBack {
    @Override
    public void processResponse() {
        System.out.println("[CallBack]:处理响应");
    }
}

Класс запроса не изменился. Основной метод в классе Main создаст экземпляр CallBackImpl и передаст его через интерфейс CallBack.

public class Main {
    public static void main(String[] args) throws Exception {
        Request request = new Request();
        System.out.println("[Main]:我开个线程去异步发请求");
        CallBack callBack = new CallBackImpl();
        new Thread(() -> {
            try {
                request.send(callBack);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }).start();
        System.out.println("[Main]:请求发完了,我去干点别的");
        Thread.sleep(100000);
    }
}

5. Лямбда-выражения

Вышеприведенные методы были введены почти. Наконец, мы представим более лаконичный способ записи. Используя лямда-выражения, нет необходимости добавлять класс реализации интерфейса CallBack. Вот посмотрите на переписанный основной метод:

public class Main {
    public static void main(String[] args) throws Exception {
        Request request = new Request();
        System.out.println("[Main]:我开个线程去异步发请求");
        new Thread(() -> {
            try {
                request.send(()-> System.out.println("[CallBack]:处理响应"));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }).start();
        System.out.println("[Main]:请求发完了,我去干点别的");
        Thread.sleep(100000);
    }
}

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

6. Резюме

Чтобы каждый мог лучше понять обратный вызов, в этой статье представлено 4 способа написания, и каждый может использовать его в соответствии со своими потребностями.

Друзья, которым нравятся мои статьи, вы можете отсканировать код и подписаться на мой официальный аккаунт: "Травяной щипок"