Interface-Designs und ihre Implementierungen

Interface als Template-Parameter

Die in den Beispielen mit rein virtuellen Interfaces und nicht rein virtuellen Interfaces beschriebenen Aufwände und die damit verbundenen Risiken lassen sich durch die Anwendung von Template-Klassen eliminieren. Der Preis dafür ist der Verzicht auf die dynamische Polymorphie, die in vielen Embedded-Softwaresystemen nicht zwingend erforderlich ist. Es ergibt sich nur eine statische Polymorphie.

Der Interface-Zugreifer tcController bekommt als Template-Parameter die Objekt- / Interfacetypen CounterA_T und CounterB_T, deren Realisierungen cUpCounter und cDownCounter er adressieren möchte. Eine direkte Abhängigkeit im Programmcode zwischen den Software-Subsystemen Controller und Counter gibt es nicht mehr. Die indirekte Abhängigkeit entsteht durch die Template-Typisierung bei der Instanziierung. Die spezifizierten Typen cUpCounter und cDownCounter müssen alles bereitstellen, was der Zugreifer tcController aufruft. Ist das nicht der Fall, meldet dies bereits der Compiler als Fehler (kein Laufzeitfehler!).

Anzeige

 

Interface Designs Bild 13 1000

Bild 13: Interface als Template-Parameter

 

Das Interface selbst ist bei diesem Interface-Design nicht eindeutig sichtbar und nur indirekt im Zugreifer durch dessen Aufrufe spezifiziert. Diese Problematik verbessert sich durch die Anwendung des Curiously Recurring Template Pattern (CRTP) [3].

Curiously Recurring Template Pattern (CRTP)

 

Interface Designs Bild 14 1000

Bild 14: CRT-Pattern

 

Die Template-Klasse tcCounter bzw. deren Funktionen repräsentieren das komplette Interface und sind vom Zugreifer tcController aufrufbar:

mobjCounterA.count();
mobjCounterB.count();

Die Interface-Funktion count() der Interface-Template-Klasse tcCounter ruft als Delegate über den Template-Parameter Realization_T die count() Funktion der realisierenden Klasse tcUpCounter bzw. tcDownCounter auf:

template <typename Realization_T>
void tcCounter<Realization_T>::count()
{
static_cast<Realization_T*>(this)->count();
}

Der Template-Parameter Realization_T wird bereits direkt bei der Vererbung von tcCounter in tcUpCounter und tcDownCounter gesetzt:

class cUpCounter   final : public tcCounter<cUpCounter>
class cDownCounter final : public tcCounter<cDownCounter>

Das Setzen eines Template-Parameters mit sich selbst als Klassentyp wird als MixedIn bezeichnet.

NL Icon 2
Jetzt die smarten News aus der IT-Welt abonnieren! 💌

Mit Klick auf den Button “Zum Newsletter anmelden” stimme ich der Datenschutzerklärung zu.

Resümee

Die Entscheidung für das „richtige“ Interface-Design ist immer von den geltenden Software-Anforderungen abhängig.

Interfaces unterstützen positiv die Umsetzung von Software-Qualitätsmerkmalen, wie beispielsweise Wiederverwendbarkeit, Portabilität, Austauschbarkeit und Erweiterbarkeit. Interface-Konzepte sind ein geeignetes Mittel zur Erfüllung von Software-Entwurfsprinzipien, z.B. lose Kopplung, Externalisierung von Abhängigkeiten, Modularisierung und Erreichen einer hohen Kohäsion.

Ein weiterführendes Konzept zu und mit Interfaces sind Ports. Ein Port vereint thematisch null bis unendlich viele bereitgestellte Interfaces und null bis unendlich viele erwartete Interfaces und lässt sich mit anderen kompatiblen Ports verbinden.

Thomas Batt

MicroConsult -

Trainer und Coach

Thomas Batt verantwortet bei MicroConsult als zertifizierter Trainer und Coach die Themenbereiche Systems/ Software Engineering für Embedded-/Realtime-Systeme sowie Entwicklungsprozess-Beratung.
Anzeige

Weitere Artikel

Jetzt die smarten News aus der IT-Welt abonnieren! 💌

Mit Klick auf den Button “Zum Newsletter anmelden” stimme ich der Datenschutzerklärung zu.