Как объяснить обратные вызовы на простом английском языке? Чем они отличаются от вызова одной функции из другой функции? - PullRequest
330 голосов
/ 07 марта 2012

Как объяснить обратные вызовы на простом английском языке? Чем они отличаются от вызова одной функции из другой, принимая некоторый контекст из вызывающей функции? Как объяснить их силу начинающему программисту?

Ответы [ 32 ]

3 голосов
/ 16 марта 2012

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

При первом обратном вызове это просто обычные функции.
И, кроме того, мы вызываем эту функцию (давайте назовем ее A) из другой функции(давайте назовем это B).

Волшебство в этом заключается в том, что я решаю, , какую функцию следует вызывать функцией из извне B.

В то время, когда я пишуфункция BI не знает, какую функцию обратного вызова следует вызвать.В то время, когда я вызываю функцию BI, я также говорю этой функции вызывать функцию A. Это все.

3 голосов
/ 14 марта 2012

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

3 голосов
/ 12 марта 2012

На простом английском языке обратный вызов - это обещание. Джо, Джейн, Дэвид и Саманта вместе едут на машине. Джо сегодня за рулем. У Джейн, Дэвида и Саманты есть несколько вариантов:

  1. Проверяйте окно каждые 5 минут, чтобы увидеть, нет ли Джо
  2. Продолжай делать свое дело, пока Джо не позвонит в дверь.

Вариант 1: Это больше похоже на пример опроса, в котором Джейн застряла бы в «петле», проверяя, находится ли Джо снаружи. Тем временем Джейн больше ничего не может сделать.

Вариант 2: Это пример обратного вызова. Джейн говорит Джо позвонить в дверь, когда он на улице. Она дает ему «функцию», чтобы позвонить в дверь. Джо не нужно знать, как работает дверной звонок или где он находится, ему просто нужно вызвать эту функцию, то есть позвонить в дверной звонок, когда он там.

Обратные вызовы управляются «событиями». В этом примере «событие» - это прибытие Джо. Например, в Ajax событиями могут быть «успех» или «отказ» асинхронного запроса, и каждый из них может иметь одинаковые или разные обратные вызовы.

С точки зрения приложений JavaScript и обратных вызовов. Нам также необходимо понимать «замыкания» и контекст приложения. То, к чему относится «это», может легко запутать разработчиков JavaScript. В этом примере в методе / обратном вызове каждого человека «ring_the_door_bell ()» могут быть некоторые другие методы, которые каждый человек должен сделать на основе своей утренней рутины ex. "выключить телевизор()". Мы бы хотели, чтобы «this» ссылалось на объект «Jane» или «David», чтобы каждый мог настроить все, что им нужно сделать, прежде чем Джо поднимет их. Это где настройка обратного вызова с Джо требует пародии метода, так что «this» относится к нужному объекту.

Надеюсь, это поможет!

2 голосов
/ 16 мая 2017

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

Обратный вызов в C с использованием указателя функции

В C обратный вызов реализован с использованием указателя функций. Указатель на функцию - как следует из названия, является указателем на функцию.

Например, int (* ptrFunc) ();

Здесь ptrFunc - указатель на функцию, которая не принимает аргументов и возвращает целое число. НЕ забывайте ставить в круглые скобки, иначе компилятор будет считать, что ptrFunc - это обычное имя функции, которое ничего не берет и возвращает указатель на целое число.

Вот некоторый код для демонстрации указателя функции.

#include<stdio.h>
int func(int, int);
int main(void)
{
    int result1,result2;
    /* declaring a pointer to a function which takes
       two int arguments and returns an integer as result */
    int (*ptrFunc)(int,int);

    /* assigning ptrFunc to func's address */                    
    ptrFunc=func;

    /* calling func() through explicit dereference */
    result1 = (*ptrFunc)(10,20);

    /* calling func() through implicit dereference */        
    result2 = ptrFunc(10,20);            
    printf("result1 = %d result2 = %d\n",result1,result2);
    return 0;
}

int func(int x, int y)
{
    return x+y;
}

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

Полная программа имеет три файла: callback.c, reg_callback.h и reg_callback.c.

/* callback.c */
#include<stdio.h>
#include"reg_callback.h"

/* callback function definition goes here */
void my_callback(void)
{
    printf("inside my_callback\n");
}

int main(void)
{
    /* initialize function pointer to
    my_callback */
    callback ptr_my_callback=my_callback;                        
    printf("This is a program demonstrating function callback\n");
    /* register our callback function */
    register_callback(ptr_my_callback);                          
    printf("back inside main program\n");
    return 0;
}

/* reg_callback.h */
typedef void (*callback)(void);
void register_callback(callback ptr_reg_callback);


/* reg_callback.c */
#include<stdio.h>
#include"reg_callback.h"

/* registration goes here */
void register_callback(callback ptr_reg_callback)
{
    printf("inside register_callback\n");
    /* calling our callback function my_callback */
    (*ptr_reg_callback)();                               
}

Если мы запустим эту программу, вывод будет

Это программа, демонстрирующая функцию обратного вызова. внутри register_callback внутри my_callback обратно в основную программу

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

Обратный вызов в Java с использованием интерфейса

В Java нет понятия указателя на функцию Он реализует механизм обратного вызова через механизм интерфейса Здесь вместо указателя на функцию мы объявляем интерфейс, имеющий метод, который будет вызван, когда вызываемый объект завершит свою задачу

Позвольте мне продемонстрировать это на примере:

Интерфейс обратного вызова

public interface Callback
{
    public void notify(Result result);
}

Абонент или класс более высокого уровня

public Class Caller implements Callback
{
Callee ce = new Callee(this); //pass self to the callee

//Other functionality
//Call the Asynctask
ce.doAsynctask();

public void notify(Result result){
//Got the result after the callee has finished the task
//Can do whatever i want with the result
}
}

Функция Callee или нижнего уровня

public Class Callee {
Callback cb;
Callee(Callback cb){
this.cb = cb;
}

doAsynctask(){
//do the long running task
//get the result
cb.notify(result);//after the task is completed, notify the caller
}
}

Обратный вызов с использованием шаблона EventListener

  • Элемент списка

Этот шаблон используется для уведомления от 0 до n номеров Наблюдателей / Слушателей о том, что конкретное задание завершено

  • Элемент списка

Разница между механизмом обратного вызова и механизмом EventListener / Observer заключается в том, что при обратном вызове вызываемый абонент уведомляет единственного абонента, тогда как в Eventlisener / Observer вызываемый может уведомить любого, кто заинтересован в этом событии (уведомление может быть передано другому части приложения, которые не вызвали задачу)

Позвольте мне объяснить это на примере.

Интерфейс событий

public interface Events {

public void clickEvent();
public void longClickEvent();
}

Виджет класса

package com.som_itsolutions.training.java.exampleeventlistener;

import java.util.ArrayList;
import java.util.Iterator;

public class Widget implements Events{

    ArrayList<OnClickEventListener> mClickEventListener = new ArrayList<OnClickEventListener>(); 
    ArrayList<OnLongClickEventListener> mLongClickEventListener = new ArrayList<OnLongClickEventListener>();

    @Override
    public void clickEvent() {
        // TODO Auto-generated method stub
        Iterator<OnClickEventListener> it = mClickEventListener.iterator();
                while(it.hasNext()){
                    OnClickEventListener li = it.next();
                    li.onClick(this);
                }   
    }
    @Override
    public void longClickEvent() {
        // TODO Auto-generated method stub
        Iterator<OnLongClickEventListener> it = mLongClickEventListener.iterator();
        while(it.hasNext()){
            OnLongClickEventListener li = it.next();
            li.onLongClick(this);
        }

    }

    public interface OnClickEventListener
    {
        public void onClick (Widget source);
    }

    public interface OnLongClickEventListener
    {
        public void onLongClick (Widget source);
    }

    public void setOnClickEventListner(OnClickEventListener li){
        mClickEventListener.add(li);
    }
    public void setOnLongClickEventListner(OnLongClickEventListener li){
        mLongClickEventListener.add(li);
    }
}

Кнопка класса

public class Button extends Widget{
private String mButtonText;
public Button (){
} 
public String getButtonText() {
return mButtonText;
}
public void setButtonText(String buttonText) {
this.mButtonText = buttonText;
}
}

Флажок класса

public class CheckBox extends Widget{
private boolean checked;
public CheckBox() {
checked = false;
}
public boolean isChecked(){
return (checked == true);
}
public void setCheck(boolean checked){
this.checked = checked;
}
}

Класс занятий

пакет com.som_itsolutions.training.java.exampleeventlistener;

public class Activity implements Widget.OnClickEventListener
{
    public Button mButton;
    public CheckBox mCheckBox;
    private static Activity mActivityHandler;
    public static Activity getActivityHandle(){
        return mActivityHandler;
    }
    public Activity ()
    {
        mActivityHandler = this;
        mButton = new Button();
        mButton.setOnClickEventListner(this);
        mCheckBox = new CheckBox();
        mCheckBox.setOnClickEventListner(this);
        } 
    public void onClick (Widget source)
    {
        if(source == mButton){
            mButton.setButtonText("Thank you for clicking me...");
            System.out.println(((Button) mButton).getButtonText());
        }
        if(source == mCheckBox){
            if(mCheckBox.isChecked()==false){
                mCheckBox.setCheck(true);
                System.out.println("The checkbox is checked...");
            }
            else{
                mCheckBox.setCheck(false);
                System.out.println("The checkbox is not checked...");
            }       
        }
    }
    public void doSomeWork(Widget source){
        source.clickEvent();
    }   
}

Другой класс

public class OtherClass implements Widget.OnClickEventListener{
Button mButton;
public OtherClass(){
mButton = Activity.getActivityHandle().mButton;
mButton.setOnClickEventListner(this);//interested in the click event                        //of the button
}
@Override
public void onClick(Widget source) {
if(source == mButton){
System.out.println("Other Class has also received the event notification...");
}
}

Основной класс

public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Activity a = new Activity();
OtherClass o = new OtherClass();
a.doSomeWork(a.mButton);
a.doSomeWork(a.mCheckBox);
}
}

Как видно из приведенного выше кода, у нас есть интерфейс с названием events, который в основном перечисляет все события, которые могут произойти для нашего приложения. Класс Widget является базовым классом для всех компонентов пользовательского интерфейса, таких как Button, Checkbox. Эти компоненты пользовательского интерфейса являются объектами, которые фактически получают события из кода платформы. Класс Widget реализует интерфейс Events, а также имеет два вложенных интерфейса: OnClickEventListener & OnLongClickEventListener

Эти два интерфейса отвечают за прослушивание событий, которые могут произойти в компонентах пользовательского интерфейса, полученных из виджетов, таких как Button или Checkbox.Таким образом, если мы сравним этот пример с более ранним примером Callback с использованием интерфейса Java, эти два интерфейса будут работать как интерфейс Callback.Таким образом, код более высокого уровня (Здесь Activity) реализует эти два интерфейса.И всякий раз, когда событие происходит с виджетом, будет вызываться код более высокого уровня (или метод этих интерфейсов, реализованный в коде более высокого уровня, который здесь называется Activity).

Теперь позвольте мне обсудить основное различие междуШаблон обратного вызова и Eventlistener.Как мы уже упоминали, используя Callback, Callee может уведомить только одного абонента.Но в случае шаблона EventListener любая другая часть или класс приложения может регистрироваться для событий, которые могут происходить на кнопке или флажке.Примером такого класса является класс OtherClass.Если вы увидите код OtherClass, вы обнаружите, что он зарегистрировал себя в качестве прослушивателя ClickEvent, что может происходить в кнопке, определенной в Activity.Интересно то, что помимо Activity (Вызывающий объект), этот OtherClass также будет уведомляться всякий раз, когда происходит событие нажатия кнопки.

2 голосов
/ 14 марта 2012

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

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

2 голосов
/ 11 марта 2012

Обратный вызов - это метод, который планируется выполнить при выполнении условия.

Примером "реального мира" является местный магазин видеоигр. Вы ждете Half-Life 3. Вместо того, чтобы каждый день ходить в магазин, чтобы посмотреть, нет ли в нем, вы регистрируете свою электронную почту в списке, чтобы получать уведомления о появлении игры. Электронная почта становится вашим «обратным вызовом», а условие, которое необходимо выполнить, - это доступность игры.

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

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

1 голос
/ 07 марта 2012

[отредактировано], когда у нас есть две функции, скажем functionA и functionB , если functionA зависит от functionB .

затем мы вызываем functionB как функцию обратного вызова . Это широко используется в среде Spring.

callback function wikipedia example

1 голос
/ 11 марта 2012

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

Меньше жесткого кода = проще в обслуживании и изменении = меньше времени = больше ценности для бизнеса = удивительность.

Например, в javascript, используя Underscore.js, вы можете найти все четные элементы в массиве, например так:

var evens = _.filter([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
=> [2, 4, 6]

Пример любезно предоставлен Underscore.js: http://documentcloud.github.com/underscore/#filter

1 голос
/ 17 марта 2012

Думайте о методе как о предоставлении задания коллеге. Простое задание может быть следующим:

Solve these equations:
x + 2 = y
2 * x = 3 * y

Ваш коллега старательно выполняет математику и дает вам следующий результат:

x = -6
y = -4

Но у вашего коллеги есть проблема, он не всегда понимает нотации, такие как ^, но он понимает их по их описанию. Такие как exponent. Каждый раз, когда он находит один из них, вы получаете следующее:

I don't understand "^"

Это требует, чтобы вы снова переписали весь набор инструкций после объяснения того, что символ означает для вашего коллеги, и он не всегда помнит между вопросами. И он с трудом запоминает ваши советы, например, просто спросите меня. Однако он всегда следует вашим письменным указаниям.

Вы думаете о решении, вы просто добавляете следующее во все ваши инструкции:

If you have any questions about symbols, call me at extension 1234 and I will tell you its name.

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

0 голосов
/ 24 апреля 2017

Функции обратного вызова:

Мы определяем callback function с именем callback, присваиваем ему параметр otherFunction и вызываем его внутри тела функции.

function callback(otherFunction){
    otherFunction();
}

Когда мы вызываем функцию callback, она ожидает аргумент типа function, поэтому мы вызываем ее с помощью анонимной функции.Однако выдает ошибку, если аргумент не относится к типу function.

callback(function(){console.log('SUCCESS!')}); 
callback(1); // error

Пример выпечки пиццы.печь для выпечки основы для пиццы с добавлением ингредиентов Теперь здесь oven - это callback functionpizza base with ingredients - это otherFunction.

Отметьте, что состоит в том, что разные ингредиенты пиццы производят разные виды пиццы, но печь, в которой она выпекается, остается прежней,Это в некоторой степени работа callback function, которая продолжает ожидать функции с разными функциональными возможностями для получения различных пользовательских результатов.

...