Du hast sicher auch schon, gerade wenn du dich etwas weiter mit der Programmierung beschäftigst, den Begriff "Objektorientierte Programmierung", kurz OOP, gehört oder gelesen. Dieses Konzept ist gerade in der Programmiersprache Java weit verbreitet und findet auch hohen Anklag.
Doch was ist das eigentlich? Was bedeutet das konkret und wie wird das umgesetzt? Genau darüber möchte ich in diesem Artikel sprechen.
Die objektorientierte Programmierung ist grundsätzlich erstmal ein sogenanntes Programmier-Paradigma. Ein Paradigma beschreibt einen bestimmten Ansatz oder Stil, um Probleme zu lösen und Software zu entwickeln. Die zwei der bekanntesten Paradigmen sind objektorientiere sowie prozeduale Programmierung.
Daneben gibt es auch noch weitere Paradigmen, die ich der Vollständigkeit halber hier aufgelistet habe.
Wie aus der Übersicht schon deutlich wird, basiert die objektorientierte Programmierung auf vier Prinzipien: Kapselung, Vererbung, Polymorphie sowie Abstraktion.
Doch zunächst einen Schritt zurück denn wir müssen zunächst einmal klären, was ist denn so ein Objekt überhaupt? Das lässt sich relativ leicht erklären, denn ein Objekt ist nichts anderes als eine Darstellung von etwas aus der realen Welt.
Okay, ich sehe ein, dass das irgendwie komisch klingt aber lass mich das anhand eines Beispiels erklären:
Denk mal an eine Schule, irgendeine Schule. Dann ist diese Schule zunächst mal ein Objekt. So eine Schule hat Schüler - auch diese sind Objekte. So eine Schule hat beispielsweise auch einen Direktor - auch dieser ist, du ahnst es schon, ein Objekt. Das trifft also grundsätzlich erstmal auf alle "Dinge" zu - alle Dinge sind Objekte.
Alle Dinge, also Objekte, haben immer bestimmte Eigenschaften, sogenannte Attribute, und die meisten haben auch ein Verhalten, können also irgendetwas tun.
In Java werden Objekte durch Klassen repräsentiert:
public class Schule {
}
mit entsprechenden Attributen:
public class Schule {
private String name;
private String schulform;
}
So lassen sich Objekte in Java erstellen. So auch beispielsweise für einen Schüler:
public class Schueler {
private String vorname;
private String nachname;
private int klasse;
}
Objekte können aber wiederum auch andere Objekte als Attribute haben. So kann die Schule auch eine Liste von Schülern haben:
public class Schule {
private String name;
private String schulform;
private List<Schueler> schuelerList;
}
Wie du sehen kannst, ist es relativ einfach solche Objekte zu erstellen und dazu gehört auch, dass dieses Paradigma relativ leicht verständlich ist. Zusammen mit sauberem Code (z.B. der Verwendung von sprechenden Variablen) lässt sich das auf den ersten Blick erkennen und lesen.
Auch ein Prinzip der objektorientierte Programmierung haben wir bereits verwendet: Kapselung. Die Attribute unseres Objekts sind alle privat, die kleinste Sichtbarkeit, was garantiert, dass von außen diese Attribute nicht verändert werden können. Will man aber, dass bestimmte Eigenschaften änderbar sind, wird das durch sogenannte Getter & Setter ermöglich. Diese Methoden sind public (von außen sichtbar) und können zur Änderung der Attribute verwendet werden.
Neben der bereits angesprochenen und verwendeten Kapselung ist ein weiteres, wichtiges Prinzip der objektorientierten Programmierung die Vererbung. Hierdurch können wir gemeinsame Eigenschaften zusammenfassen und diese an die Kind-Klassen vererben.
Bleiben wir beim Beispiel der Schule. Grundsätzlich können wir sagen, dass es verschiedene Arten von Schulen gibt, z.B. Grundschulen, weiterführende Schulen oder Berufsschulen. Und auch wenn es völlig verschiedene Arten von Schulen sind, haben sich auch Gemeinsamkeiten. Jede Schule hat immer auch einen Namen und auch Schüler. Diese gemeinsamen Eigenschaften werden dann in der Oberklasse Schule deklariert. Alle Klassen, die von dieser Schule erben, verfügen dann automatisch über diese Eigenschaften und können zusätzlich auch noch eigene Eigenschaften haben.
public class Schule {
private String name;
private List<Schueler> schuelerListe;
}
public class Grundschule extends Schule {
private Spielplatz spielplatz;
}
public class Gesamtschule extends Schule {
private Mensa mensa;
}
public class Berufsschule extends Schule {
private Kiosk kiosk;
}
Hier haben wir also die Oberklasse Schule mit einem Namen und einer Liste von Schülern. Die Kindklassen Grundschule, Gesamtschule und Berufsschule erben nun von Schule (extends) und haben daher alle auch diese zwei Attribute. Zusätzlich haben sie noch eigene Attribute.
Auch wenn eine Kindklasse keinerlei eigene Attribute haben sollte ist es immer sinnvoll, diese als eigene Klassen zu implementieren um deutlich zu machen, dass es sich um eine konkrete Implementierung einer Schule handelt.
Das dritte von vier Prinzipien der objektorientierten Programmierung ist die Polymorphie. Mit diesem Prinzip haben wir die Möglichkeit, Methoden unterschiedlich zu "interpretieren". So kann es sein, dass die Klasse Schule eine Methode zum Versetzen eines Schülers hat. Diese Methode kann in der Schule-Klasse definiert worden sein und behandelt damit eine normale Versetzung eines Schülers ins nächste Schuljahr. Jetzt kann es durchaus möglich sein, dass die Art und Weise, wie ein Schüler versetzt wird, je nach Schultyp unterschiedlich ist.
public class Schule {
...
public void versetzeSchueler(Schueler schueler) {
// Standard-Versetzung in die nachste Klasse
}
}
public class Grundschule extends Schule {
...
@Override
public void versetzeSchueler(Schueler schueler) {
// hier wird unabhängig von den Noten immer ins naechste Schuljahr versetzt
}
}
Mit diesem Prinzip ist es uns möglich, einmal definierte Methoden in der Oberklasse, in den Unterklassen unterschiedlich zu implementieren zu können. Dies nennt man überschreiben und wird mit einer @Override-Annotation versehen um dies kenntlich zu machen.
Das vierte und letzte Prinzip ist die Abstraktion. Hier ist das gängiste Methode die Verwendung von Interfaces. Klassen können immer nur von einer Klasse erben, aber mehrere Interfaces implementieren.
In einem Interface können beispielsweise Methode definiert werden, die in den Klassen, die das Interface implementieren zwingend definiert, also implementiert, werden müssen. Um beim Beispiel der Schulen zu bleiben können wir uns vorstellen, dass jede Schule über eine Pausenglocke verfügt. Jede Schule hat aber einen unterschiedlichen Glocken-Ton aber läuten müssen sie alle.
Also definieren wir und ein Interface:
public interface IPausenGlocke {
void laeuten();
}
Normalerweise werden Interfaces immer mit einem Adjektiv beschrieben und enden - auf englisch - meist mit "-able" oder der Name beginnt mit einem großen "I" um auf den ersten Blick erkennbar zu machen, dass es sich bei dieser Klasse um ein Interface handelt. Wir wir auch sehen können, verfügt die deklarierte Methode "laeuten" über keinen Methodenbody. Dieser muss beim Implementieren der Methode in den Klassen implementiert werden.
public class Grundschule extends Schule implements IPausenGlocke {
...
@Override
public void laeuten() {
System.out.println("Glocke macht BimBim");
}
}
public class Berufsschule extends Schule implements IPausenGlocke {
...
@Override
public void laeuten() {
System.out.printl("Glock macht DingDong");
}
}
So haben wir die Möglichkeit zu definieren, welche Methoden alle Arten von Schulen haben müssen, können aber die konkreten Details dazu individuell bestimmen.
Ähnlich wie Interfaces verhält es sich mit abstrakten Klassen die auch Teil der Abstraktion sind. Im Gegensatz zu Interfaces sind dies aber Klassen die nicht Instanziiert werden können - das bedeutet aber auch, dass eine Klasse entweder von einer Oberklasse oder einer abstrakten Klasse erben kann. Die Verwendung ist in meiner Wahrnehmung aber selten, daher gehe ich nicht im Detail darauf ein sondern belasse es bei der Erwähnung. Mehr zur abstrakten Klassen kannst du hier oder hier finden.
Wie du siehst, ist objektorientierte Programmierung kein Hexenwerk wenn man sich die vier Prinzipien Kapselung, Vererbung, Polymorphie und Abstraktion vor Augen hält. Lediglich die Entscheidung und das Wissen, wann und in welchem Fall man welches Prinzip anwendet kann immer von Einzelfall abhängen und erfordert ein wenig Erfahrung.
Mit der ojektorientierten Programmierung bist du aber in der Lage, deine Anwendung schön unterteilen uns lesbarer zu machen. Alles hat einen sprechenden Namen und man sieht sofort, was du zeigen und "modellieren" willst. Auch wird dein Code dadurch wesentlich wartbarer weil auch fremde deinen Code sofort überschauen und interpretieren können.
Bitte beachte, dass hier nur die wesentlichen Bestandteile von mit angeschnitten wurden. Für ein tieferes Verständnis empfehle ich dir, zusätzlich diese Seiten anzusehen:
Hilfreiche Links:
- Einstieg in die Objektorientierung in Java
- Einführung in die Grundlagen der objektorientierten Programmierung in Java
- Java Programmieren lernen: Objektorientierte Programmierung in Java einfach erklärt
Hast du schon Erfahrungen mit der objektorientierten Programmierung gemacht? Welches waren oder sind deine Herausforderungen? Lass es mich gern in den Kommentaren wissen.
