Zum Inhalt springen

API-Design

Wählen Sie jede Designoption aus, die die folgende Anforderung erfüllt:

Anforderung: Ein Callback sollte standardmäßig als parallelisierbar betrachtet werden, und die API sollte dieses Standardverhalten widerspiegeln.

Stellen wir uns zunächst vor, wie die Registrierung eines Callbacks unter jedem Design aussehen würde.

// Option 1
events.register(|e: OnClick| { /* .. */ });
events.register_sequential(|e: OnClick| { /* .. */ })
// Option 2
events.register(Callback::Parallel(|e: OnClick| { /* .. */ }));
events.register(Callback::Sequential(|e: OnClick| { /* .. */ }));
// Option 3
events.register(|e: OnClick| { /* .. */ });
events.register(|_: Sequential, e: OnClick| { /* .. */ });

Von diesen Optionen vermitteln Option 1 und 3, dass parallel der Standardmodus ist, da dies der einfachsten Option entspricht. Sequenziell zu sein erfordert entweder die Verwendung eines längeren Methodennamens (_sequential) oder eines Marker-Typs (_: Sequential).

Option 2 kennzeichnet nicht eindeutig, dass parallel der Standard sein sollte, da sowohl Parallel als auch Sequential an register übergeben werden müssen.


Wählen Sie jede Designoption aus, die die folgende Anforderung erfüllt:

Anforderung: Die API sollte so wenige Methoden wie möglich exportieren.

Optionen 2 und 3 exportieren nur eine einzige register-Methode. Option 1 erfordert den Export von zwei unterschiedlich benannten register-Methoden.


Wählen Sie jede Designoption aus, die die folgende Anforderung erfüllt:

Anforderung: Die API sollte so wenig wie möglich auf das Typinferenzsystem des Compilers angewiesen sein.

Optionen 1 und 2 erfordern nicht viel Typinferenz, außer der Bestimmung des Typs der Funktion F.

Option 3 verwendet einen Überladungs-Trick, indem ein Register-Trait erstellt wird, der über einen „Marker“-Typ parametrisiert ist. Erinnern Sie sich an die beiden register-Aufrufe:

events.register(|e: OnClick| { /* .. */ })
events.register(|_: Sequential, e: OnClick| { /* .. */ })

Diese sehen so aus, als würden sie dieselbe Implementierung verwenden, aber sie beziehen sich tatsächlich auf verschiedene Implementierungen derselben Methode. Diese Implementierung verlässt sich darauf, dass der Compiler den Typ von Marker inferiert, wenn er auflöst, welcher Implementierung von Register jeder .register(..)-Aufruf entspricht. Wenn unser Ziel also ist, sich nicht auf Typinferenz zu verlassen, dann ist Option 3 ungeeignet.