Interface Konzept in C
-
Hallo Leute,
gerade sitze ich vor einer Aufgabe durch die ich an die Grenzen meiner „Erfahrung“ gekommen bin und mich deshalb sehr über externen Input/Schlagworte freuen würde.
Die Aufgabe: In einem Programm werden verschiedene Funktionen (f1(), f2()..) aufgerufen. Die Implementierung der Funktionen hängt von einigen Parametern ab, die sich in eher seltenen Fällen ändern. Wenn sich ein Parameter ändern, muss bisher eine andere Version des Programmes mit den richtigen Implementierungen her. Ich soll eine Art Interface entwerfen, sodass man immer das gleiche Programm hat, dem man dann über eine Konfiguration(sdatei) je nach Parameter zur Laufzeit die richtigen Implementierungen zuweist.
Lösungsansatz1 (trivial): In jeder Funktion gibt es ein riesiges Switch-Case das über den Parameter die richtige Funktion wählt. Problem: man hat ewig viel Code und auch viele Redundanzen drin, da z.B. durch einen Parameter 5 Implementierungen festgelegt werden für jedes aber ein eigenes Swich-case gebraucht wird.
Lösungsansatz2(nicht umsetzbar, kompliziert, der eilige Leser kann das hier getrost überspringen): Man schreibt eine .h Datei für jeweils alle Funktionen die von einem Parameter abhängig sind. Über diese Header Dateien werden dem Hauptprogramm die Funktionen bekannt gemacht. Für jeden Parameter schreibt man jetzt eine .c Datei, in der eben die richtige Implementierung drin ist. Jetzt macht man aus jedem .C-Datei ein Objektfile (kann man ja in verschiedene Ordner, damit man keine Probleme wegen der Namengleichheit). Dann benennt man jedes Objektfile um, zB ursprünglich hießen alle „wichtigesmodul.o“ und nun „wichtigesmodul_A.o“, „wichtigesmodul_B.o“.. und pakt alle Objektfile wieder in einen Ordner. Nun kann je nach Parameter aus der Konfigurationsdatei ein anderes Skript aufgerufen werden, dass das entsprechende Objektfile umbenennen und mit dem Hauptprogramm linkt.
Wie angedeutet ist das hier ziemlich kompliziert. Ich kann mit dem gcc umgehen, aber richtig auswendig kenn ich ihn nicht (z.B. kann man einen Pfad zu der Datei angeben statt umbenennen und in einen Ordner verschieben?) Zudem werde ich in dem Endprojekt nicht den Einfluss haben, dass man irgendwelche Skripte aufrufen kann, die den Linker in Aktion setzten. Und zur Laufzeit ist es auch nicht. Ist eher ein Denk-Gesponnte. Also ja, das ist Mist.
Sinn des Abschnitts: Hab versucht mir nach dem Buch „C Interfaces and Implementations“ von David R. Hanson das „Interface-Konzept“ Trennung von.c und.h Dateien irgendwie nützlich zu machen. Laut ihm ist das das einzige was C bietet. Also wäre das geprüft. Jede Richtung an Ideen werden verfolgtLösungsansatz3: (der beste) Man arbeitet mit Function Pointern. Ganz am Anfang liest man die Konfigaus und über ein Switch-Case werden die richtigen Funktionen für die Parameter den Funktion Pointern zugewiesen. Man hat großes Switch-case, sehr viel weniger Code wie bei Lösung1 und trotzdem ist es recht einfach. Das Ganze ist Zentral in einer Init-Funktion und besser wartbar. Im Hauptprogramm kann dann ganz normal / einfach die Function Pointer aufgerufen werden.
Soweit die Lösungsansätze die ich zusammentragen konnte. Fällt jemandem noch etwas ein? Ich hoffe die Texte / Beispiele sind unterstützend nicht verwirrend / nur Ballast.
Ich freu mich auf Denkanstöße und Ideen.
(Sry dass es so lang wurde, das Thema ist etwas abstrakt. Leider habe ich auch keine Spoiler zur Strukturierung gefunden)
-
Mal sehen, ob ich das richtig verstanden haben.
Du hast mehrere Funktionen f1(), f2(), f3(), ...
Von Jeder Funktion gibt es mehrere Versionen f1.1(), f1.2(), f1.3(), ...
Die verschiedenen f1.x() haben alle denselben Aufruf und liefern dieselbe Art Ergebnis zurück. (Desgleichen für f2.x(), f3.x() ...)
Jede f1.x() kann auch mit jeder f2.y(), f3.z(), ... in Kombination auftreten oder
gibt es eine bestimmte Zusammenstellung?
-
Genau alle Versionen der Funktionen liefern das gleiche Ergebnis zurück. Es gibt gewisse Zusammenhänge weswegen eben in „lösungsansatz1“ sehr starke Resonanzen auftreten. Zum Beispiel kann man sich eine Funktion
setF(int i)
,int getF()
undboolean controll_If_F_isValid()
vorstellen. Ihre Implementierung würde alle vom gleichen Parameter abhängen, nämlich was F ist und wie man darauf zugreift (in Lösungsansatz1hat man also quasi 3 mal die gleiche switch-case-struktur). Die Implementierung vonint operateOnE()
wäre davon aber komplett unabhängig, also sind alle Kombinationen zwischen E- und F-funktionen denkbar.In C++ würde ich zwei Interface E und F schreiben, dass dann die Klassen ImplementationE1, ImplementationE2 und ImplementationE3, bzw ImplementationF1, ImplementationF2 und ImplementationF3 implementieren. Zwei Factory Methode entscheidet dann anhand des Parameters welche Klasse zurück gegeben wird, deren Methoden dann im Hauptprogramm aufgerufen werden. Alle Methoden eine Klasse mit gleichem Interface sind natürlich abhängig von einander, aber die Klassen an sich nicht.
Aber ich mag C, muss auch wegen hardwarenähe in C schreiben und muss auch überhaupt nicht in der Weise der OOP denken (siehe Lösungsansatz2).
-
Dein Vorschlag 3 ist doch supi.
Wenn ich das jetzt richtig verstanden habe, ist das Problem und dessen Lösung als Strategy-Pattern in die Softwareliteratur eingegangen.
Du wirst also einen Haufen von structs mit Funktionspointern haben, die Du richtig initialisierst und los geht's. Z.B.
struct F{ void (*setF)(int i); int (*getF)(void); boolean (*controll_If_F_isValid)(void); };
-
Furble Wurble schrieb:
Dein Vorschlag 3 ist doch supi.
Wenn ich das jetzt richtig verstanden habe, ist das Problem und dessen Lösung als Strategy-Pattern in die Softwareliteratur eingegangen.
Du wirst also einen Haufen von structs mit Funktionspointern haben, die Du richtig initialisierst und los geht's. Z.B.
struct F{ void (*setF)(int i); int (*getF)(void); boolean (*controll_If_F_isValid)(void); };
So hatte ich mir das auch vorgestellt, dürfte ne saubere Sache werden.
Die Frage ist nur ob es Alternativen gibt, bessere oder schlechtere. Vermute c gibt da noch was her, auf das ich halt mangels Erfahrung mit Interfaces nicht komme.