2 OOP für Fortgeschrittene


[Seminarübersicht]...[Entwurfsmuster nach Gamma]...[3 Wie ein Entwurfsmuster aussieht]

Das Verstehen der grunglegenden Prinzipien (z.B.: Kapselung) und Techniken (z.B.: Vererbung) der objektorientierten Programmierung bereitet normalerweise keine großen Schwierigkeiten. Damit ist es jedoch noch nicht getan. Die eigentliche Leistung des Entwicklers besteht darin, die bereitgestellten Techniken auf die richtige Art und Weise nutzbringend einzusetzen. Im folgenden werden wichtige Aspekte der objektorientierten Entwicklung erläutert, die zum Verständnis und zum Gebrauch der Entwurfsmuster wichtig sind.


Der Unterschied zwischen Klassenvererbung und Schnittstellenvererbung

Dieser Unterschied wird in verschiedenen Sprachsystemen verschieden realisiert bzw. nicht realisiert.
Bei der Klassenvererbung erhält das Kindobjekt alle Variablen, sowie die Methoden inclusive ihrer Implementierung. Analog hierzu erhält das Kindobjekt bei der Schnittstellenvererbung nur die
Signaturen der Methoden, nicht aber deren Implementierung. Dies wird auch als "Subtyping" bezeichnet, da eine Klasse, die die abgeleitete Schnittstelle implementiert, unter anderem vom Typ der beerbten Schnittstelle ist, also alle ihre Anfragen (typischerweise darüber hinaus mehr) erfüllt.
In den Mustern und in gängigen oo-Sprachsystemen, die keinen expliziten Unterschied bei der Vererbung machen, wird die Schnittstellenvererbung durch das Erben von abstrakten Klassen nachgebildet.


Möglichkeiten der Wiederverwendung von Code
- Klassenvererbung und Objektkomposition -

Bei der Klassenvererbung erbt eine Unterklasse die Implementierung und den Typ ihrer Oberklasse (s.o.). Dem Kindobjekt können neue Variablen und Methoden hinzugefügt werden und somit ist eine Wiederverwendung realisiert. Diese Technik der Wiederverwendung ist auch als White-Box-Wiederverwendung bekannt, da die Struktur des Elternobjektes eingebunden wird und somit bekannt ist.

Die Objektkomposition hingegen basiert auf der Technik, Objekte bestehender Klassen in eine Struktur einzubeziehen (z.B. durch Aggregation oder Referenz). Da hier nur die Schnittstelle des Objektes bekannt ist, wird diese Art von Wiederverwendung auch als Black-Box-Wiederverwendung bezeichnet.

Die Klassenvererbung ist Teil der Programmiersprache und somit einfach zu realisieren. Die geerbten Methoden können beibehalten oder überschrieben werden, die Variablen werden ergänzt, genutzt oder "links liegen gelassen". Hier läßt sich schon erahnen, daß die Klassenvererbung zu unsauberem Programmierstil verleiten kann.

Die Vorteile der Objektkomposition liegen ganz klar in der Flexibilität: Beziehungen zwischen Objekten lassen sich (im Gegensatz zu denen zwischen Klassen) zur Laufzeit dynamisch erzeugen und verwerfen. Weiterhin sind die beteiligten Objekte nur durch die Schnittstelle bekannt und somit gegen solche gleicher Schnittstelle austauschbar, ohne daß auf die unterschiedlichen Implementierungen Rücksicht genommen werden muß (sofern die Spezifikation erfüllt bleibt !). Für die Nutzung der Wiederverwendung durch Objektkomposition spricht weiterhin, daß die Klassenvererbung die Klassenhierarchie verkompliziert. Es werden Abhängigkeiten geschaffen. Jede Veränderung der Implementierung oder Struktur einer Vorfahr-Klasse wirkt sich auf die erbende Klasse aus.

Natürlich hat der ganze Vergleich einen Haken: Er ist eigentlich gar nicht notwendig, da diese zwei Techniken beide zur Anwendung kommen müssen, und zwar jede dann, wenn es angezeigt ist. Es muß eine Klassenhierarchie existieren, um überhaupt erst Objekte zur Objektkomposition ableiten zu können. Da jedoch die Erfahrung (u.a. die der "Gang Of Four") lehrt, daß zu selten der kompliziertere Weg der Objektkomposition (hier bedarf es einer sauberen Schnittstellendefinition und deren Einhaltung) gewählt wird, sollte jeder Entwickler die Möglichkeiten und Konsequenzen beider Techniken kennen. Das Wissen um den richtigen Einsatz beider Techniken bedarf einer gewissen Erfahrung, die letzten Endes einen Experten ausmacht. Das Durcharbeiten der Muster ist insofern auch für unerfahrene Entwickler sinnvoll, die dadurch für die Feinheiten des oo-Entwurfes "sensibilisiert" werden.


Delegation

Mit Hilfe der Delegation (von Anfragen) kann auch mittels Objektkomposition ein Verhalten simuliert werden, welches sonst nur über Vererbung realisiert werden kann.

Um dies erklären zu können, benutze ich ein Beispiel, welches bereits ein Entwurfsmuster gebraucht (Zustandsmuster):

In einer Software wird eine Datei mittels eines Objektes repräsentiert. Da sich der Zustand einer Datei ändern kann (offen/geschlossen), muß sich auch das Verhalten des entsprechenden Objektes ändern (Das Öffnen einer offenen Datei bzw. das Schließen einer geschlossenen ist sicherlich grober Unfug !)
Eine Möglichkeit, dies in einem objektorientierten Entwurf zu implementieren, besteht darin, Eine
abstrakte Klasse "Datei" einzuführen, von der eine konkrete Klasse "OffeneDatei" und eine andere "GeschlosseneDatei" abgeleitet werden. So werden die abstrakten Methoden, wie beispielsweise "Oeffne()" oder "Schliesse()" überschrieben und das unterschiedliche Verhalten ist realisiert.

In dieser starren Hierarchie stellt aber die Änderung des Dateizustandes eine Hürde dar. Ein Objekt müßte die Klasse wechseln, was nicht möglich ist. Man müßte ein Objekt der jeweils gewünschten Klasse erzeugen, die Variablen umkopieren, etc. Und selbst dann bekommt man in einem komplexen Entwurf eventuell noch Probleme mit existenten Referenzen und wird so zu weiteren Änderungen gezwungen.
Der Lösungsansatz des Zustandsmusters besteht darin, ein Datei-Objekt einzuführen, welches diejenigen Daten bzw. Operationen enthält, die kontextunabhängig sind. Weiterhin erhält dieses Objekt eine Referenz (meist Aggregationsbeziehung) auf ein "Zustandsobjekt", in welchem die zustandsabhängigen Operationen implementiert sind.
Die verschiedenen Zustandsklassen stammen von einer abstrakten Klasse ab.

Nun ist der Fortbestand eines Datei-Objektes unabhängig von seinem Zustand gesichert. Lediglich bei Veränderungen des Zustandes sind Veränderungen in der Objektstruktur nötig. Diese Struktur ist zur Laufzeit dynamisch und hat somit das übergeordnete Ziel des objektorientierten Entwurfs schon erreicht.



[Seminarübersicht]...[Entwurfsmuster nach Gamma]...[3 Wie ein Entwurfsmuster aussieht]...[Seitenanfang]