Angenommen, Sie wollen eine Prozedur zur Integration einer reellen Funktion schreiben f ( x ) über ein Intervall [a, b]. Nehmen wir an, wir wollen dazu die 3-Punkt-Gauß-Methode verwenden (natürlich ist jede andere Methode geeignet).
Idealerweise wollen wir eine Funktion, die wie folgt aussieht:
// 'f' is the integrand we want to integrate over [a, b] with 'n' subintervals.
static double Gauss3(Integrand f, double a, double b, int n) {
double res = 0;
// compute result
// ...
return res;
}
Wir können also eine beliebige Integrand
, f und ihr definitives Integral über das geschlossene Intervall erhalten.
Nur welche Art sollte Integrand
sein?
Ohne Delegierte
Nun, ohne Delegierte bräuchten wir eine Art von Schnittstelle mit einer einzigen Methode, sagen wir eval
wie folgt erklärt:
// Interface describing real-valued functions of one variable.
interface Integrand {
double eval(double x);
}
Dann müssten wir eine ganze Reihe von Klassen erstellen, die diese Schnittstelle implementieren, wie folgt:
// Some function
class MyFunc1 : Integrand {
public double eval(double x) {
return /* some_result */ ;
}
}
// Some other function
class MyFunc2 : Integrand {
public double eval(double x) {
return /* some_result */ ;
}
}
// etc
Um sie dann in unserer Gauss3-Methode zu verwenden, müssen wir sie wie folgt aufrufen:
double res1 = Gauss3(new MyFunc1(), -1, 1, 16);
double res2 = Gauss3(new MyFunc2(), 0, Math.PI, 16);
Und Gauss3 muss wie folgt aussehen:
static double Gauss3(Integrand f, double a, double b, int n) {
// Use the integrand passed in:
f.eval(x);
}
Wir müssen also all das tun, nur um unsere willkürlichen Funktionen in Guass3
.
Mit Delegierten
public delegate double Integrand(double x);
Jetzt können wir einige statische (oder nicht) Funktionen definieren, die diesem Prototyp entsprechen:
class Program {
public delegate double Integrand(double x);
// Define implementations to above delegate
// with similar input and output types
static double MyFunc1(double x) { /* ... */ }
static double MyFunc2(double x) { /* ... */ }
// ... etc ...
public static double Gauss3(Integrand f, ...) {
// Now just call the function naturally, no f.eval() stuff.
double a = f(x);
// ...
}
// Let's use it
static void Main() {
// Just pass the function in naturally (well, its reference).
double res = Gauss3(MyFunc1, a, b, n);
double res = Gauss3(MyFunc2, a, b, n);
}
}
Keine Schnittstellen, kein klobiges .eval-Zeug, keine Objektinstanziierung, nur eine einfache Verwendung von Funktionszeigern für eine einfache Aufgabe.
Natürlich sind Delegierte mehr als nur Funktionszeiger unter der Haube, aber das ist ein anderes Thema (Funktionsverkettung und Ereignisse).