Zitat von
ice.icewing:
Bernhard Geyer hat hier im Forum bereits öfter darauf hingewiesen das ein Brückenmuster (Bridge Pattern) der beste Weg ist eine Unterstützung mehrerer
DBMS in einem Projekt zu realisieren. Ich habe diesen Vorschlag aufgenommen, komme aber jetzt bei der Umsetzung ins Stocken.
Hi,
vor deinem Beispiel und den dort beschriebenen Problemen steht natürlich das Verständnis des Musters, deswegen vorab einmal die Frage, wie weit Du es bereits verstanden hast?
Die Frage
Zitat von
ice.icewing:
Es ist wirklich wichtig für mich die Zusammenhänge zu verstehen und anwenden zu können. Wenn jemand eine Deklaration oder ein Beispiel für mich hat welches auch Vererbung nutzt würde mir das sehr helfen.
lässt (soweit ich Dich nicht falsch verstehe) ein wenig darauf schließen, dass Du hier noch nicht ganz sicher bist.
Ein eigentlich ganz schönes Beispiel, dass Du häufig als Anwendungsbeispiel findest, können wir ja mal näher betrachten. Das Typische Beispiel (das ich jetzt kenne) ist immer die Darstellung von Formen.
Hier sind zwei Dinge wichtige:
- Die Darstellung
- Die Formen
Fangen wir mit der linken Seite an. Hier steht die Abstraktion. Wie der Name unschwer vermuten lässt, möchte man als von etwas Konkreten abstahieren und mit dem Abstrakten (den Gemeinsamkeiten) arbeiten. Die Abstraktion besteht in diesem Fall aus den Formen. Formen gibt es unzählige, ich verzichte mal auf eine all zu große Aufzählung, denke jeder kennt Ellipsen und Vielecke zu genüge.
Das ich sagen kann, dass ein Dreieck, ein Viereck, ein Kreis, ... Formen sind, das zeigt, dass Formen etwas gemeinsames haben. Um einen Kreis zu beschreiben brauche ich aber (i.d.R.) andere Dinge als wenn ich ein Dreieck oder Viereck beschreiben möchte. Die Abstraktion wäre in diesem Fall jedenfalls die Form, ihre Eigenschaften fässt man in einer abstrakten Klasse zusammen. Eine Eigenschaft, die jede Form z.B. hat ist ihre Größe, ihr Flächeninhalt, was auch immer. Eine der wichtigsten Eigenschaften ist dann noch, dass man Formen zeichnen kann. Hier stellt sich die Frage, wie man dies idealerweise tut.
Eine einfache Idee wäre es, dass man eine Bibliothek diese Aufgabe übernehmen lässt, diese Bibliothek zeichnet dann einfach alle Formen. Das Problem, dass man dann aber natürlich hat ist, dass man nicht alle Formen kennt. So gibt es zu jeder natürlichen Zahl >= 3 ein entsprechendes Vieleck (mit entsprechend vielen Punkten). Und dann wären noch die Kombinationen aus allen Formen möglich...
Da man nicht alle Formen kennt, die auftreten könnten, lässt man einfach die Formen die Aufgabe des Zeichnens übernehmen. Jede Form weiß natürlich wie sie aussieht. Sie kann sich also ohne Probleme selbst darstellen.
Das ist auch schon alles, was wir über die linke Seite wissen, es gibt eine abstrakte Klasse Form, die hat bestimmte Eigenschaften (Größe, Position, ...) und kann sich selbst zeichnen. Von dieser Abstrakten Klasse erben jetzt ganz unterschiedliche Formen (alle die halt erstellt werden).
Nun müssen wir uns noch Gedanken zum Zeichnen machen. Wie gesagt, alle Nachfahren einer Form können sich zeichnen, die Frage ist aber wie. Wie man zeichnet hängt wiederum sehr stark vom System ab, auf dem die Anwendung läuft. So unterscheidet sich natürlich
OpenGL von
DirectX oder
GDI. Auch hier gibt es also verschiedene Möglichkeiten. Das zeichnen für jede dieser Grafik-Schnittstellen und für jede Form zu implementieren wäre sicherlich keine schöne Aufgabe (und würde den Sinn der Abstraktion Form auch stark in Frage stellen).
Einschränkungen der verwendeten Zeichenroutinen sind aber natürlich auch nicht gerade von Vorteil. Nehmen wir einfach an, dass Du z.B. gerne mit
GDI+ zeichnen möchtest, weil es schnell und schön ist. Auf älteren Windowssystemen muss diese Bibliothek aber nicht vorhanden sein. Hier möchtest Du aber dem Benutzer auch nicht den Download zumuten, sondern verwendest das vermeintlich langsamere
GDI, das aber anders arbeitet.
Je nach System würde also anders gezeichnet werden.
Was Du an dieser Stelle machst ist aber einfach davon abstrahieren. Du beachtest nicht weiter, wie jetzt tatsächlich gezeichnet wird sondern schaffst eine Schnittstelle Zeichnen, die davon abstrahiert. Diese Schnittstelle ist dann deine Impelementierung, das Zeichnen mit
GDI oder
GDI+ sind dann die konkreten Implementierungen.
Was jetzt noch fehlt ist die Zusammenführung. Möchte ein Objekt vom Typ Form sich selbst zeichnen, dann holt es sich über eine bestimmte Methode der abstrakten Klasse einfach eine Zeichnen Instanz. Zeichnen entscheidet selbst für das entsprechende System, ob
GDI oder
GDI+ verwendet wird (je nachdem was vorhanden ist). Die konkrete Form bekommt jedenfalls durch den Aufruf einer bestimmten Methode ein Zeichnen-Objekt und weiß, wie es das benutzt. Dieser Weg (wie man an dieses Objekt kommt) ist für alle Formen gleich!
So, was Du jetzt hast sind einfach zwei Unabhängige Abstraktionen. Steigst Du für die Darstellung auf GTK+ um, so benötigst Du dazu nur eine andere Implementierung der Schnittstelle Zeichnen. Für die Formen bleibt dies aber hinter der Schnittstelle verborgen, sie bekommen ein Objekt, dass alle Funktionen der Schnittstelle Zeichnen zur Verfügung stellt.
Auf der anderen Seite gibt es aber auch ganz unterschiedliche Formen, mit völlig unterschiedlichen Eigenschaften, aber eben auch Gemeinsamkeiten, zu denen eben auch in Teilen das Zeichnen gehört (natürlich zeichnet sich ein Rechteck etwas anders als ein Kreis).
Ja, das ist es auch schon. Idee ist also, dass Du zwei Abstraktionen benutzt. Die linke (die auch als Abstraktion bezeichnet wird) ist dabei eine abstrakte Klasse, die auf die Implementierung (rechte) zugreift. Hinter der Implementierung können sich aber wiederum konkrete Implementierungen verbergen. Da die linke Abstraktion zudem abstrakt ist, muss es hier sogar konkrete Nachfahren geben, also auch hier hinter verbergen sich verschiedene Implementierungen.
Ja, wie gesagt, es ist erstmal wichtig diese Idee zu verstehen. Falls Du noch Fragen hast, stell sie einfach. Für Dein Beispiel wäre es schön, wenn Du nochmal sagst, was für Dich die Abstraktion und konkrete Abstraktionen und was die Implementierung/konkrete Implementierungen sind und warum. Da ist es dann vermeintlich leichter den Überblick zu behalten (hatte heute zuwenig Kaffe und hab dein Beispiel nur überflogen, da ist mir gerade nicht mehr klar, wer jetzt von wem erben soll).
Gruß Der Unwissende