Apel invers (programare)

Versiunea actuală a paginii nu a fost încă examinată de colaboratori experimentați și poate diferi semnificativ de versiunea revizuită la 21 ianuarie 2021; verificările necesită 3 modificări .

Callback ( în engleză  call  - call, English  back  - reverse) sau funcția de apel invers în programare  - trecerea codului executabil ca unul dintre parametrii altui cod. Callback-ul permite funcției să execute codul care este specificat în argumente atunci când este apelată. Acest cod poate fi definit în alte contexte de cod și nu poate fi apelat direct din această funcție. Unele sarcini algoritmice au ca intrare nu numai numere sau obiecte, ci și acțiuni (algoritmi), care sunt specificate în mod natural ca apeluri inverse.

Aplicație

Conceptul de apel invers are multe aplicații. De exemplu, unii algoritmi (funcții) au ca subsarcină sarcina de a calcula o valoare hash dintr-un șir. În argumentele la pornirea algoritmului (funcției), este convenabil să specificați ce funcție să utilizați pentru a calcula valorile hash.

Un alt exemplu de algoritm pentru care este firesc să treci o funcție ca argument este un algoritm pentru parcurgerea unui depozit de obiecte, aplicând o anumită acțiune fiecărui obiect. Un apel invers poate acționa ca această acțiune (algoritm).

Tehnica de programare callback în limbaje de programare precum C este simplă. Când funcția principală este apelată, i se trece pur și simplu un pointer către funcția de apel invers. Exemplul clasic este o funcție qsortdin biblioteca stdlib . Această funcție sortează o matrice de blocuri de octeți de aceeași lungime. Ca argumente, primește adresa primului element al matricei, numărul de blocuri din matrice, dimensiunea blocului de octeți și un pointer către o funcție pentru a compara două blocuri de octeți. Această funcție de comparație este funcția de apel invers din acest exemplu:

#include <stdlib.h> // functie de comparare intregi modulo int compare_abs ( const void * a , const void * b ) { int a1 = * ( int * ) a ; int b1 = * ( int * ) b ; return abs ( a1 ) - abs ( b1 ); } int main () { int dimensiune = 10 ; int m [ mărime ] = { 1 , -3 , 5 , -100 , 7 , 33 , 44 , 67 , -4 , 0 }; // sortarea matricei m în module crescătoare qsort ( m , size , sizeof ( int ), compare_abs ); returnează 0 ; }

Vă puteți gândi la un apel invers ca la o acțiune transmisă ca argument unei proceduri principale. Și această acțiune poate fi văzută ca:

  • subsarcină și să fie utilizate pentru prelucrarea datelor în cadrul acestei proceduri;
  • „Conexiune telefonică” folosită pentru „contact” cu cel care a apelat procedura atunci când are loc un eveniment (în engleză  callback se traduce literalmente prin „call back”).

Exemplul prezentat mai sus corespunde exact primului caz. Cazul în care apelarea inversă este utilizată ca „conexiune telefonică” reflectă codul în care este dată funcția de a gestiona un anumit semnal:

#include <stdio.h> #include <semnal.h> volatil sig_atomic_t br = 1 ; void sig ( int signum ) { br = 0 ; } int main ( int argc , char * argv []) { semnal ( SIGINT , sig ); printf ( "Apăsați combinația de taste break pentru a opri programul \n " ); în timp ce ( br ); printf ( "SIGINT primit, ieșire \n " ); returnează 0 ; }

În unele limbaje de programare, cum ar fi Common Lisp , Erlang , Scheme , Clojure , PHP , JavaScript , Perl , Python , Ruby și altele, este posibil să se construiască funcții anonime (nenumite) și funcții de închidere chiar în expresia principală a apelului de funcție și această oportunitate este utilizată pe scară largă.

În tehnologia AJAX , atunci când faceți o solicitare asincronă către server, trebuie să specificați o funcție de apel invers care va fi apelată de îndată ce sosește răspunsul la cerere. Adesea, această funcție este definită „la loc” fără a-i da vreun nume specific:

Ajax nou . Solicitare ( 'http://example.com/do_it' , { method : 'post' , onSuccess : function ( transport ) { // funcția apelată de fereastră . alert ( „Done!” ); // dacă solicitarea a avut succes } , // onFailure : function () { // functia apelata de window . alertă ( "Eroare!" ); // la cerere eroare de execuție } });

Funcția de apel invers este utilizată și în modelul de design Observer . Deci, de exemplu, folosind biblioteca Prototype , puteți crea un „observator” care monitorizează clicurile pe un element cu un identificator "my_button"și, atunci când este primit un eveniment, scrie un mesaj în interiorul elementului "message_box":

eveniment . observe ( $ ( "my_button" ), 'click' , function () { $ ( "message_box" ). innerHTML = "Ai dat clic pe butonul!" });

Funcția de apel invers este o alternativă la polimorfismul funcției , și anume, vă permite să creați funcții cu un scop mai general, în loc să creați o serie de funcții care sunt aceleași ca structură, dar diferă doar în anumite locuri în subtask-urile executabile. Funcțiile care preiau alte funcții drept argumente sau returnează funcții ca rezultat sunt numite funcții de ordin superior . Tehnica de apel invers joacă un rol important în reutilizarea codului .

De ce să folosiți apelurile inverse

Pentru a înțelege mai bine motivele utilizării unui apel invers, luați în considerare sarcina simplă de a efectua următoarele operații pe o listă de numere: imprimați toate numerele, pătrați toate numerele, creșteți toate numerele cu 1, setați toate elementele la zero. Este clar că algoritmii pentru efectuarea acestor patru operații sunt similari - aceasta este o buclă care ocolește toate elementele listei cu o anumită acțiune în corpul buclei, aplicată fiecărui element. Acesta este un cod simplu și, în principiu, îl puteți scrie de 4 ori. Dar să luăm în considerare un caz mai complicat, când lista nu este stocată în memorie, ci pe disc, iar mai multe procese pot funcționa cu lista în același timp și este necesar să se rezolve problemele de sincronizare a accesului la elemente (mai multe procese pot efectuați diferite sarcini - eliminarea unor elemente din listă, adăugarea altora noi, modificarea elementelor existente în listă). În acest caz, sarcina de a parcurge toate elementele listei va fi un cod destul de complex pe care nu ar dori să îl copiați de mai multe ori. Ar fi mai corect să se creeze o funcție de uz general pentru parcurgerea elementelor listei și să le permită programatorilor să facă abstracție de la modul în care funcționează algoritmul de traversare și să scrie doar o funcție de apel invers pentru procesarea unui singur element al listei.

Structurarea software -ului

Structurarea software-ului prin funcții de apel invers este o abordare foarte convenabilă și utilizată pe scară largă, deoarece comportamentul unui program cu cod neschimbat (inclusiv închis) poate fi modificat într-o gamă foarte largă. Acest lucru este implementat în două moduri - fie prin „implementarea alternativă” a unei funcții, fie prin „adăugarea unei alte funcții la lanțul de apeluri”.

De regulă, dezvoltatorul nu implementează toată funcționalitatea programului prin apeluri inverse, ci doar cea care ar trebui să fie extinsă sau modificată de pluginuri . Pentru conectarea pluginurilor este prevăzută o procedură specială, care înlocuiește funcțiile inverse „standard” de la dezvoltator cu altele alternative de la plugin.

Cel mai faimos exemplu al acestei abordări este sistemul de operare Microsoft Windows , unde funcțiile de apel invers sunt numite „handler” („handler”) și este posibil să se introducă o procedură suplimentară între oricare două standard. Această abordare se numește „interceptare a evenimentelor” și este folosită, de exemplu: de către antivirusuri pentru a verifica fișierele care sunt accesate; viruși pentru citirea caracterelor introduse de la tastatură; filtre de rețea pentru a colecta statistici și a bloca pachete.

În sistemele moderne Unix și Linux , este posibilă încărcarea și descărcarea dinamică a modulelor de kernel, care se bazează și pe funcții de apel invers. În același timp, există un modul (extensie kernel) FUSE , care, la rândul său, oferă posibilitatea programelor de utilizator obișnuite de a servi (intercepta) solicitările către sistemele de fișiere virtuale.

În software, uneori există o descompunere a programelor care se bazează complet pe funcții de apel invers, ceea ce înrăutățește ușor lizibilitatea codului, dar oferă oportunități maxime pentru pluginuri. Un exemplu de astfel de produs este DokuWiki .

Avantaje și dezavantaje

Avantaje:

  • Posibilitatea de schimbare dinamică a funcționalității (conectarea și deconectarea plug-in-urilor/modulelor în timpul rulării programului).
  • Posibilitatea unui număr nelimitat de variante ale funcției apelate fără modificarea codului de bază (în acest context).
  • Abilitatea de a insera o funcție apelată nu numai pentru un comportament alternativ, ci și ca o altă subrutină (intermediară) - de obicei pentru a urmări operațiunile sau a modifica parametrii pentru următoarea funcție (numită). În lanțul de apeluri poate exista orice număr de astfel de „legături suplimentare” independente.
  • Suport pentru funcțiile de apel invers în majoritatea limbajelor de programare moderne de uz general.

Defecte:

  • Penalizarea de performanță asociată cu apelurile suplimentare de „funcție inversă” este direct proporțională cu „costul apelului de funcție” în timpul execuției și cu numărul de apeluri suplimentare în timpul rulării programului.
  • Deteriorarea lizibilității codului sursă - pentru a înțelege algoritmul programului, este necesar să urmăriți întregul lanț de apeluri.

Vezi și

Link -uri