Freitag, 16. Mai 2014

Program to an Interface - totale 1:n-Interfaces

"Program to an interface, not an implementation." Erstes Prinzip des objektorientierten Entwurfs, [GOF1995].
Im vorigen Blogartikel haben wir Interfaces in vier Kategorien eingeteilt. Von diesen behandeln wir im vorliegenden Artikel totale 1:n-Interfaces:
  • totale 1:1-Interfaces
  • totale 1:n-Interfaces
  • notwendig partielle Interfaces
  • freiwillig partielle Interfaces
In welchen Fällen ist es vorteilhaft, ein totales 1:n-Interface und nicht unmittelbar die einzelnen Implementierungen zu verwenden?

Vermeidung redundanter Fallunterscheidungen

Ein typischer Fall für die Verwendung totaler 1:n-Interfaces besteht in der Anwendung des Single Choice Prinzips. Im Rahmen der Behandlung dieses von Bertrand Meyer formulierten Prinzips hatten wir bereits festgestellt, dass die Vermeidung redundanter Fallunterscheidungen mittels Polymorphie und dynamischer Bindung einen positiven Einfluss auf eine Reihe von Qualitätsmerkmalen ausübt. Derartige Fallunterscheidungen können beispielsweise die Auswahl zwischen einer Familie ähnlicher Entitäten oder Algorithmen betreffen.

Die Alternative bestünde in einem irgendwie gearteten Auswahlmechanismus für die konkreten Implementierungen, der sich möglicherweise redundant über zahlreiche Module verteilen würde. Das totale 1:n-Interface ermöglicht es den Aufrufenden, sich auf ihre eigene Verantwortlichkeit zu konzentrieren, während der Auswahlmechanismus für die Instantiierung der passenden Implementierung von einer anderen Einheit übernommen wird, die für diese Aufgabe besser geeignet ist. Als Auswahlmechanismus kommen beispielsweise eine abstrakte Fabrik, ein Objekt-Repository oder generische Programmiertechniken in Betracht.

Das Single Choice Prinzip liefert also ein starkes Ergänzungs-Kriterium zu Program to an Interface.

Offenheit für Erweiterungen

Mehrere Implementierungen stehen für mehrere Variationen eines bestimmten Sachverhalts oder Vorgangs. Dabei ist es grundsätzlich nicht unwahrscheinlich, dass zur Entwurfszeit nicht alle Variationen erkannt werden oder dass im Laufe der Benutzung des Systems neue Variationsmöglichkeiten entstehen. Es muss demnach auf einfache Weise möglich sein, neue Variationen hinzuzufügen. Dies ist eine zentrale Forderung des Open-Closed Prinzips

Angewandt auf die Terminologie von Aufrufern und Aufgerufenen ermöglicht es das Open-Closed Prinzip den Aufrufern, geschlossen zu bleiben, während das Interface offen für Erweiterungen (nämlich zusätzliche Implementierungen) bleibt. Welches andere Konstrukt könnte diese Offenheit gewährleisten? Im Katalogeintrag zum Open-Closed Prinzip wurden u. a. Closures, Plugin-Architekturen oder das Vorsehen von User-Exits genannt. Insofern solche Möglichkeiten naheliegen, können sie durchaus Alternativen zur Verwendung totaler 1:n-Interfaces sein. Dennoch ist die Verwendung von Interfaces in Sprachen, die abstrakte Typen zur Verfügung stellen, eine vergleichsweise einfach realisierbare Möglichkeit.

Das Open-Closed Prinzip liefert demnach ein weiteres Ergänzungs-Kriterium zu Program to an Interface.

Austausch per Konfiguration

Ein häufiger Spezialfall totaler 1:n-Interfaces sieht wie folgt aus:


Zur produktiven Laufzeit des Systems wird ausschließlich die ProduktiveImplementierung als Aufgerufene verwendet. Unter anderen Ausführungsbedingungen, insbesondere im Rahmen der Ausführung von Tests oder während der Entwicklungsarbeit kann jedoch auch Mock zum Einsatz kommen. Der Austausch der Implementierung erfolgt in einer solchen Konstellation oftmals durch die Konfiguration der Ausführungsumgebung wie beispielsweise test- oder entwicklungsspezifische Dependency Injection. Während zur Laufzeit eigentlich ein totales 1:1-Interface vorliegt, enthält die Codebasis doch mehrere Implementierungen, so dass der Charakter eines totalen 1:n-Interfaces entsteht.

Zusammenfassung

Polymorphie und dynamische Bindung bilden die technische Grundlage für die elegante Lösung der besprochenen Konstellationen:
  • redundanzfreie Fallunterscheidungen zur Laufzeit des Systems (Single Choice Prinzip)
  • Offenheit für Erweiterungen über die Lebenszeit des Systems (Open-Closed Prinzip)
  • Austausch von Implementierungen zur Konfigurationszeit des Systems (z. B. per Dependency Injection)
Besteht mindestens eine dieser Konstellationen oder aber ein weiterer Anwendungsfall für Polymorphie und dynamische Bindung, so ist dies ein starkes Kriterium für die Einführung eines totalen 1:n-Interfaces.

Siehe auch

Alle Artikel der Serie "Program to an Interface ...":

Einführung
Kategorisierung von Interfaces
Totale 1:n-Interfaces
Totale 1:1-Interfaces
Freiwillig partielle Interfaces
Notwendig partielle Interfaces
Fazit und Gegenbeispiele
Interface oder abstrakte Klasse?
Werkzeugunterstützung
Das Prinzip

Quellen

[GOF1995] - Design Patterns - Elements of Reusable Software, E. Gamma, R. Helm, R. Johnson, J. Vlissides, (Addison‐Wesley, 1995).