Grundlagen der Programmierung: Entwurfsmuster

Auffrischung Objektorientierung

Testen Sie unsere 2007 Kurse

10 Tage kostenlos!

Jetzt testen Alle Abonnements anzeigen
Dieses Video wiederholt und erläutert die wichtigsten Konzepte der Objektorientierung.
09:00

Transkript

Mit diesem Video können Sie Ihr Wissen über die Grundlagen der Objektorientierung auffrischen. Wir beginnen mit Objekten und Klassen, widmen uns dann der Vererbung mit Oberklassen und Unterklassen, wiederholen kurz das Konzept der Polymorphie und werfen schließlich noch einen kurzen Blick auf abstrakte Klassen und Schnittstellen. Beginnen wir mit Objekten und Klassen. Die Basis einer jeden objektorientierten Anwendung sind natürlich Objekte. Objekte zeichnen sich durch zwei wesentliche Elemente aus, nämlich Attribute und Methoden. Die Attribute, die sich sozusagen im Inneren des Objekts befinden, sind seine Eigenschaften. Sie stellen also den internen Zustand des Objekts dar. Die Methoden sind die Fähigkeiten des Objekts, also das Verhalten, das es an den Tag legt, wenn andere Objekte mit ihm kommunizieren. Um beschreiben zu können, wie Objekte aussehen, gibt es Klassen. Klassen sind also die Baupläne für Objekte. Hier steht also drinnen, welche Attribute ein Objekt haben soll, welche Methoden und was passieren soll, wenn diese Methoden aufgerufen werden. Nach einem solchen Bauplan lassen sich dann nach Bedarf beliebig viele Objekte erzeugen. Diese Klassen werden also vom Entwickler zur Entwicklungszeit erstellt, wohingegen die Objekte zur Laufzeit von der Laufzeitumgebung erzeugt werden. Damit kommen wir zum zweiten Punkt der Vererbung. Vererbung ermöglicht es Codedopplungen zu vermeiden und gemeinsames Verhalten in separate Klassen auszulagern. Schauen wir uns als Beispiel diese beiden Klassen an. Wir haben hier eine Klasse Auto mit ein paar Methoden beschleunigen, bremsen, anhalten und hupen. Dann haben wir eine zweite Klasse Cabrio. Cabrio hat Methoden zum Beschleunigen, zum Bremsen, zum Anhalten, zum Hupen und Methoden zum Öffnen und Schließen des Cabriodachs. Wie sie sehen können, sind die ersten vier Methoden in beiden Klassen enthalten und das Cabrio hat dann noch zwei zusätzliche Methoden. Statt die Klasse Auto zu kopieren und dadurch den ganzen Code zweimal zu haben, können wir stattdessen Vererbung einsetzen. Cabrio wird als Unterklasse von Auto deklariert und erbt so alles, was in Auto bereits drinnen ist. Auto ist die Oberklasse von Cabrio und Cabrio ist die Unterklasse von Auto. Das Cabrio hat somit von vornherein dieselben Methoden, dieselbe Funktionalität wie Auto und wir müssen lediglich die beiden neuen Methoden öffneDach und schließeDach hinzufügen. Unterklassen können aber nicht nur das geerbte Verhalten um zusätzliche Methoden erweitern, sondern auch geerbtes Verhalten verändern. Um das zu demonstrieren haben ich der Klasse Auto eine weitere Methode hinzugefügt, nämlich getStatus. Diese Methode liefert einen kurzen Text, der den aktuellen Status des Objektes beschreibt. In diesem Fall also die aktuelle Geschwindigkeit. In der Unterklasse möchten wir dieses Verhalten jetzt nicht einfach nur erben, wir möchten auch nicht extra eine neue Methode getCabrioStatus hinzufügen müssen, sondern wir wollen das geerbte Verhalten verändern. Der Status soll nun zusätzlich angeben, ob das Cabriodach geöffnet oder geschlossen ist. Dazu wird die geerbte Methode überschrieben. Das heißt, wir fügen in der Unterklasse eine Methode mit genau derselben Signatur hinzu. So liefert der Cabriostatus nun tatsächlich die gewünschten Informationen. In diesem speziellen Fall wird ein Teil der Informationen, die das Cabrio liefern soll eigentlich bereits von Auto zur Verfügung gestellt. Es ließe sich hier also noch etwas kürzer schreiben, indem ich mir diese Informationen auch vom Auto abhole. Damit ist das Beispiel komplett. Das Auto liefert als Status erst mal die Geschwindigkeit und ergänzt das Ganze dann noch um den aktuellen Zustand des eigenen Daches. Eines der Kernkonzepte der Objektorientierung ist die Polymorphie. Auch das lässt sich am besten wieder in einem Beispiel erklären, diesmal direkt im Quelltext. Diesmal haben wir sogar drei Klassen. Die erste ist die Klasse Auto. Wir sehen hier das Attribut für die Geschwindigkeit und einige der Methoden, die ein solches Auto zur Verfügung stellt. Als nächstes folgt die Klasse Cabrio als Unterklasse von Auto. Das heißt, Cabrio erbt zuerst alles, was in Auto bereits vorhanden ist. Wir sehen hier das zusätzliche Attribut dachOffen. Wir sehen die überschriebene Methode getStatus und wir sehen die beiden zusätzlichen Methoden öffneDach und schließeDach, die nur in Cabrio vorhanden sind. Der Dritte im Bunde ist die Klasse Mechaniker. Der Mechaniker hat eine Methode. Das ist die Methode überprüfen und die nimmt ein Auto und überprüft dieses Auto dann irgendwie. Der Mechaniker könnte zum Beispiel das Auto beschleunigen und bremsen und er könnte sich den aktuellen Status holen um zu überprüfen, ob alles korrekt funktioniert. Wenn wir nun also ein Autoobjekt haben und ein Mechanikerobjekt, dann kann der Mechaniker von diesem Autoobjekt zum Beispiel getStatus aufrufen. Der Mechaniker bekommt die Referenz auf das Auto hier als Parameter in der Methode übergeben. Nun bauen wir uns ein Cabrio. Ein Cabrio ist zuerst einmal ein Auto. Das heißt, das hier ist der Autoteil des Cabrios und das wird dann ergänzt um die zusätzlichen Dinge, die spezifisch für das Cabrio sind. In unserem Fall also das neue Attribut, die beiden neuen Methoden. Da das Cabrio ein Auto ist, kann ich ein solches Cabrio auch an die Methode überprüfen übergeben und der Mechaniker kann ebenfalls zum Beispiel die Methode getStatus aufrufen. Hier kommt jetzt die Polymorphie ins Spiel. Das Autoobjekt weiß, dass es ein Auto ist. Das Cabrioobjekt weiß, dass es ein Cabrio ist. Das heißt, wenn der Mechaniker vom Auto getStatus aufruft, dann wird diese Methode aktiviert. Ruft er hingegen vom Cabrio getStatus auf, dann wird die getStatus Methode aus der Klasse Cabrio aktiviert. Der Mechaniker spricht beide Objekte als Auto an. Auto ist auch der Typ, den er kennt. Das heißt, für den Mechaniker bieten beide Objekte auch dieselbe Schnittstelle an. Das tatsächliche Verhalten, das wir bekommen, hängt aber davon ab, was es zur Laufzeit konkret für ein Objekt ist, also ob es ein Auto ist oder ob es ein Cabrio ist. Polymorphie heißt also sozusagen, ich spreche verschiedene Objekte über dieselbe Schnittstelle an und welches Verhalten ich bekomme, hängt einfach davon ab, was zur Laufzeit konkret für ein Objekt dahinter sitzt, aber das muss der Mechaniker nicht wissen. Für den ist nur interessant, dass alle diese Objekte eben dieselbe Schnittstelle anbieten, also dieselben Methoden. Da der Mechaniker aber nun nur den Typ Auto kennt und nichts von Cabrios weiß oder von irgendwelchen anderen Unterklassen, kann er natürlich tatsächlich nur die Methoden aufrufen, die in der Klasse Auto bereits beschrieben sind. Das heißt, sein Aufruf der Methode öffneDach wäre nicht möglich. In Java bekämen wir an dieser Stelle zum Beispiel einen Compilerfehler. Fassen wir zusammen. Jedes Objekt in einer objektorientierten Anwendung weiß selbst, wie es sich zu verhalten hat. Es weiß also selbst, was es ist, ein Auto, ein Cabrio, ein Trucker, was auch immer. Eine Referenzvariable vom Typ einer Oberklasse, also in diesem Fall Auto kann auf eine Instanz einer Unterklasse verweisen, also in diesem Fall Cabrio. Das sehen wir hier. Der Mechaniker hat eine Variable vom Typ Auto und die kann aber auf ein Cabrio verweisen. Der Typ dieser Variablen, dieser Referenzvariablen legt fest, welche Methoden aufgerufen werden können, also in unserem Fall welche Methoden der Mechaniker überhaupt sehen kann und der Typ des Objekts dahinter legt fest, welches Verhalten zur Laufzeit tatsächlich aktiviert wird. Jetzt wissen Sie also auch wieder, was es mit Polymorphie auf sich hat. Schreiten wir voran in unserer Wiederholung und werfen einen kurzen Blick auf abstrakte Klassen. Klassen sind Baupläne für Objekte. Von normalen Klasen können wir also direkt Exemplare, also Instanzen erzeugen. Abstrakte Klassen heißen deshalb so, weil sie eben abstrakt sind. Das heißt, sie sind eben nicht zur Instanziierung gedacht. Aber was nutzt eine Klasse, wenn ich sie nicht instanziieren kann? Abstrakte Klassen dienen typischerweise dazu, Basisfunktionalität zur Verfügung zu stellen für spätere Unterklassen. Wenn ich also mehrere Klassen habe und ein Teil der Funktionalität ist bei allen gleich, dann kann ich diese Funktionalität in eine abstrakte Basisklasse auslagern. Da sie nur als Rumpf dient, als Basis für die anderen Unterklassen ist sie eben nicht dazu gedacht, selbst instanziiert zu werden und wir machen sie abstrakt. Abstrakte Klassen können außerdem noch abstrakte Methoden haben. Abstrakte Methoden bestehen quasi nur aus ihrer Signatur, also dem Namen und der Parameterliste und haben keinen Rumpf, also keine Implementierung, nicht einmal eine Leerimplementierung. Auf diese Weise kann ich bereits in der Basisklasse festlegen, welche Methoden in den Unterklassen vorhanden sein müssen, ohne mich hier schon auf eine konkrete Implementierung festlegen zu müssen. Damit kommen wir zum letzten Punkt in unserem kleinen Exkurs, zu den Schnittstellen. Für das Konzept der Schnittstelle gibt es in verschiedenen Programmiersprachen verschiedene Bezeichnungen. In Java heißen sie zum Beispiel Interfaces. In Objective-C heißen beispielsweise Protocols. Das Konzept ist aber das gleiche. Ich fasse mehrere öffentliche Methoden unter einen gemeinsamen Namen zusammen, also unter einem Typ und lege auf diese Weise fest, dass ein Objekt, das diesen Typ hat, eben genau diese Methoden anbieten kann. Im Gegensatz zu einer abstrakten Klasse lege ich hier allerdings tatsächlich nur die Namen der Methoden und die Parameterlisten fest, also wirklich nur die Schnittstelle. Das, was man von außen sehen kann und ich habe keine Möglichkeit irgendwelche auch nur Teilfunktionalität in diese Schnittstellendeklaration einzubauen. Aufgrund des völligen Fehlens jeglicher Implementierung können Interfaces demzufolge natürlich nicht instanziiert werden. Variablen vom Typ des Interfaces können aber selbstverständlich angelegt werden. Ein Client, der einen bestimmten Interfacetyp kennt, kann mit allen Objekten kommunizieren, die dieses Interface anbieten, ohne dass der Client wissen muss, welche konkrete Klasse für die Erzeugung des jeweiligen Objektes verwendet wurde. Auf der einen Seite haben wir also das Dienstobjekt, das die Schnittstelle anbietet und auf der anderen Seite haben wir den Client, der das Objekt über diese Schnittstelle nutzt. Darüber hinaus müssen die beiden Seiten also nichts voneinander wissen. Damit haben wir nun die wichtigsten Grundkonzepte der Objektorientierung noch einmal durchgesprochen und Sie haben das jetzt alles wieder frisch und parat.

Grundlagen der Programmierung: Entwurfsmuster

Erhalten Sie einen fundierten Einstieg in das Thema Entwurfsmuster (Design Patterns) und erfahren Sie, wie Sie Entwurfsmuster in objektorientierten Programmiersprechen umsetzen.

2 Std. 49 min (33 Videos)
Derzeit sind keine Feedbacks vorhanden...
 

Dieser Online-Kurs ist als Download und als Streaming-Video verfügbar. Die gute Nachricht: Sie müssen sich nicht entscheiden - sobald Sie das Training erwerben, erhalten Sie Zugang zu beiden Optionen!

Der Download ermöglicht Ihnen die Offline-Nutzung des Trainings und bietet die Vorteile einer benutzerfreundlichen Abspielumgebung. Wenn Sie an verschiedenen Computern arbeiten, oder nicht den ganzen Kurs auf einmal herunterladen möchten, loggen Sie sich auf dieser Seite ein, um alle Videos des Trainings als Streaming-Video anzusehen.

Wir hoffen, dass Sie viel Freude und Erfolg mit diesem Video-Training haben werden. Falls Sie irgendwelche Fragen haben, zögern Sie nicht uns zu kontaktieren!