Rückruffunktion

aus Wikipedia, der freien Enzyklopädie
(Weitergeleitet von Callback-Funktion)

Eine Rückruffunktion (englisch Callback) bezeichnet in der Informatik eine Funktion, die einer anderen Funktion, meist einer vorgefertigten Bibliotheks- oder Betriebssystemfunktion, als Parameter übergeben und von dieser unter definierten Bedingungen mit definierten Argumenten aufgerufen wird. Dieses Vorgehen folgt dem Entwurfsmuster der Inversion of Control.

Meistens erlaubt die vorgefertigte Funktion die Übergabe eines sog. Benutzerparameters lpParameter, der von ihr (neben anderen Argumenten) zur Rückruffunktion durchgereicht wird, damit letztere im Kontext des ursprünglichen Aufrufers Daten sowohl abgreifen wie ablegen kann.

Rückruf im selben Ablauf

ProgramExecCallbackSimple-de.png

Das Bild zeigt einen Aufruf einer Routine eines anderen Kontextes (Betriebssystemaufruf, anderes Softwaremodul). Diesem Aufruf wird eine Referenz auf die Rückrufroutine übergeben. Die aufgerufene Routine kann dann in ihrem Ablauf die Rückrufroutine aufrufen. Die Rückrufroutine legt letztlich Daten ab, die im weiteren Programmablauf nach Rückkehr des ursprünglichen Aufrufes verwendet werden können. In der englischen Literatur wird diese Form als blocking callback oder synchronous callback bezeichnet.

Der Vorteil dieser Technik besteht darin, dass der Zugriff auf die Daten im eigenen Kontext formuliert wird und/oder im Rückruf eine beliebige programmtechnische Aufbereitung erfolgen kann: Die Parameter und der Aufrufzeitpunkt werden im anderen Softwaremodul bestimmt, die Bestimmung, was im Rückruf ausgeführt wird, obliegt dem eigenen Softwaremodul.

Dadurch wird ermöglicht, Funktionen allgemein zu definieren und erst beim Aufrufen der Funktion durch Angabe der Rückruffunktion das Verhalten exakt zu bestimmen. Häufig bekommt eine Rückruffunktion gar keinen Namen, sondern wird als anonyme Funktion direkt beim Aufruf definiert (siehe auch Lambda-Kalkül). Über Rückruffunktionen erreicht man eine lose Kopplung zwischen einzelnen Komponenten.

Rückruf aus einem anderen Thread

Callback mit Thread-Interkommunikation.png

Bei Angabe einer Rückruffunktion ist es der aufgerufenen Funktion überlassen, wann diese den Rückruf ausführt (Inversion of Control). Es ist möglich, dass der Rückruf zu einem späteren Zeitpunkt aus einem anderen Thread heraus erfolgt. Das nebenstehende Bild zeigt das Prinzip. Die Zuordnung der Rückrufroutine zum eigenen Kontext ist die Gleiche wie im obigen Schema. Da der Rückruf in einem anderen Thread erfolgen kann, sind aber zusätzlich die Bedingungen für eine Datenkonsistenz (Mutex) einzuhalten. In der englischen Literatur wird diese Form als deferred callback oder asynchronous callback bezeichnet.

Ein Beispiel dafür ist der Aufruf SetTimer(hWnd, ident, milliseconds, callbackRoutine) in der Windows-API. Der Aufruf SetTimer(...) ist ein kurzer Betriebssystemaufruf, der nur im Betriebssystem den Timer initialisiert. Die callbackRoutine wird erst dann aufgerufen, wenn die Zeit abgelaufen ist. Das geschieht in einem Thread des Betriebssystems unabhängig vom Ablauf nach dem Aufruf von SetTimer(...). In der bereitzustellenden Rückrufroutine kann beliebiger Code ausgeführt werden. Es ist allerdings dabei zu beachten, dass die Rückrufroutine nur kurz und nicht blockierend sein darf. Sonst besteht die Gefahr, dass das gesamte Betriebssystem oder mindestens der aktuelle Prozess blockiert. Letztlich sollte die Rückrufroutine eigentlich nur Daten ablegen und nicht selbst komplexe Aktionen beinhalten. Insbesondere kann für eine ereignisorientierte Programmierung eine Event-Instanz erzeugt und abgelegt werden, die weitere Abläufe steuert.

Dauerhafte Rückrufroutine

Eine Rückrufroutine kann nur jeweils für einen Aufruf gelten. Die Rückrufroutine kann in Bezug zum Aufruf auch mehrmals gerufen werden, bis die zugehörige Aktion beendet ist, also zeitlich begrenzt.

Aber auch die dauerhafte Zuordnung einer Routine wird teilweise als callback routine bezeichnet, beispielsweise ThreadProc callback function:[1] Bei der Anlage eines Threads über die Windows-API wird die Threadfunktion als callback function angegeben.

Die Zuordnung einer Ereignisbehandlungsroutine beispielsweise zu einem HTML-Element <button onclick="function()" /> oder zu einem Widget innerhalb einer Programmierung grafischer Benutzeroberflächen folgt demselben Schema, wird aber in diesem Zusammenhang gewöhnlich nicht als callback, sondern als event handler bezeichnet.

Einfache Rückruffunktion oder objektorientierter Rückruf

Die sogenannten callback function in der Windows-API sind jeweils einfache C-Funktionen. Die Windows-API wird als C-Schnittstelle bereitgestellt. In Foren gibt es häufig Fragen nach der Möglichkeit, C++-Funktionen zuzuordnen. Notwendig ist hier eine Kapselung des C++-Aufrufes in einer C-Funktion, die die Dateninstanz kennt.

Anders ist es in objektorientierten Ansätzen eines Rückrufes. Statt der Angabe eines Funktionszeigers wird die Referenz auf ein Datenobjekt für den Rückruf übergeben. Das Datenobjekt muss ein für den Rückruf bestimmtes Interface realisieren. Das Interface enthält dann mehrere mögliche Rückruffunktionen in der Tabelle virtueller Methoden innerhalb der Dateninstanz und kennt gleichzeitig die notwendigen Daten für die Ausführung des Rückrufes. Das Grundschema ist genau das gleiche wie in den obigen Schemata gezeigt.

Beispiele

Es soll eine Funktion apply_to geschrieben werden, die eine beliebige andere Funktion auf eine Liste von Werten anwendet und eine Liste der Ergebnisse zurückgibt. Eine Umsetzung in Pseudocode:

function apply_to (rückruffunktion, werte):
    var ergebnis; // Liste für die Ergebnisse
    foreach w in werte do // für alle Werte ...
        e = rückruffunktion (w); // rufe die Rückruffunktion ...
        ergebnis[] = e;   // und hänge das Resultat an die Ergebnisliste an.
    end;
    return ergebnis;
end apply_to;

Diese Funktion kann jetzt folgendermaßen verwendet werden:

function verdoppeln (wert): // dies ist eine Rückruffunktion
    return wert*2;
end verdoppeln;
function quadrat (wert): // dies ist eine andere Rückruffunktion
    return wert*wert;
end quadrat;
// Anwenden der Funktionen auf eine Liste:
werte = (1, 2, 3, 4);
doppelte_Werte   = apply_to(verdoppeln, werte); //ergibt (2, 4, 6, 8)
quadrierte_Werte = apply_to(quadrat, werte);    //ergibt (1, 4, 9, 16)

Oder, kürzer, in Lambda-Notation:

werte = (1, 2, 3, 4);
doppelte_Werte   = apply_to(lambda x: x*2, werte); //ergibt (2, 4, 6, 8)
quadrierte_Werte = apply_to(lambda x: x*x, werte); //ergibt (1, 4, 9, 16)

JavaScript

Rückrufe werden bei der Implementierung von Programmiersprachen wie JavaScript verwendet, einschließlich der Unterstützung von JavaScript-Funktionen als Rückrufe über js-ctypes und in Komponenten wie addEventListener.

Im folgenden Beispiel wird zunächst eine Funktionsberechnung mit einem für den Rückruf bestimmten Parameter definiert: rueckruffunktion. Dann wird eine Funktion definiert, die als Rückruf zur Berechnung verwendet werden kann: berechneSumme. Für rueckruffunktion können andere Funktionen verwendet werden, z. B. berechneProdukt. In diesem Beispiel wird berechne(...) zweimal aufgerufen, einmal mit berechneSumme als Rückruf und einmal mit berechneProdukt. Die Funktionen geben das Summe bzw. Produkt die zurück, und die Warnung zeigt sie auf dem Bildschirm an.

function berechne(zahl1, zahl2, rueckruffunktion)
{
    return rueckruffunktion(zahl1, zahl2);
}

function berechneSumme(zahl1, zahl2)
{
    return zahl1 + zahl2;
}

function berechneProdukt(zahl1, zahl2)
{
    return zahl1 * zahl2;
}

// Gibt 20, die Summe von 5 and 15, aus
alert(berechne(5, 15, berechneSumme));

// Gibt 75, das Produkt von 5 und 15, aus
alert(berechne(5, 15, berechneProdukt));

C#

public class Hauptklasse 
{
    static void Main(string[] args)
    {
        Nebenklasse objekt = new Nebenklasse();
        
        // Ruft die Methode von Nebenklasse mit Rückruffunktion als Parameter auf
        objekt.Aufrufmethode(Rueckruffunktion);
    }
    
    // Diese Rückruffunktion gibt den im Rückruf angegebenen Text aus
    static void Rueckruffunktion(string text)
    {
        Console.WriteLine("Der Rückruf lautet:" + text);
    }
}

public class Nebenklasse
{
    // Diese Methode hat eine andere Methode als Parameter und ruft diese auf
    public void Aufrufmethode(Action<string> rueckruf)
    {
        // Ruft die Methode Rueckruffunktion in Hauptklasse mit der der angegebenen Textnachricht aus
        rueckruf("Ich komme sofort zurück.");
    }
}

Siehe auch

Weblinks

Einzelnachweise