CodeGym /Java-Blog /Germany /Prinzipien der objektorientierten Programmierung
Autor
Jesse Haniel
Lead Software Architect at Tribunal de Justiça da Paraíba

Prinzipien der objektorientierten Programmierung

Veröffentlicht in der Gruppe Germany
Hallo! Hast du dich schon einmal gefragt, warum Java genau so aufgebaut ist? Dazu musst du die Prinzipien der objektorientierten Programmierung kennenlernen. Aber warum setzt sich die Sprache aus Klassen und Objekten zusammen und nicht aus etwas völlig anderem? Warum ist das Konzept des „Objekts“ entstanden und hat solch eine Bedeutung erlangt= Sind alle Programmiersprachen so aufgebaut? Wenn nicht, welche Vorteile ergeben sich für Java aus diesem Paradigma? Du siehst, ganz schön viele Fragen :) Versuchen wir, in der heutigen Lektion jede von ihnen zu beantworten.

Was ist objektorientierte Programmierung (OOP)?

Zunächst einmal sollte man wissen, dass Java nicht nur zum Spaß aus Objekten und Klassen besteht. Sie sind keine Laune der Java-Schöpfer, und nicht einmal ihre Erfindung. Es gibt viele andere Programmiersprachen, die auf Objekten basieren. Die erste derartige Sprache hieß Simula und wurde in den 1960er Jahren in Norwegen erfunden. Die Konzepte von „Klasse“ und „Methode“ tauchten erstmals in Simula auf.Prinzipien der objektorientierten Programmierung - 1Nach den Maßstäben der Softwareentwicklung erscheint Simula wie eine uralte Sprache, aber jeder kann die „familiäre Ähnlichkeit“ mit Java sehen. Du kannst wahrscheinlich leicht Code lesen, der in dieser Sprache geschrieben wurde und in groben Zügen erklären, was er tut :)

Begin
	Class Rectangle (Width, Height); Real Width, Height;
			           
	 Begin
	    Real Area, Perimeter;  
	 
	    Procedure Update;      
	    Begin
	      Area := Width * Height;
              OutText("Rectangle is updating, Area = "); OutFix(Area,2,8); OutImage;
	      Perimeter := 2*(Width + Height);
              OutText("Rectangle is updating, Perimeter = "); OutFix(Perimeter,2,8); OutImage;
	    End of Update;
	 
	    Update;               
	    OutText("Rectangle created: "); OutFix(Width,2,6);
	    OutFix(Height,2,6); OutImage;
	 End of Rectangle;

       Rectangle Class ColouredRectangle (Color); Text Color;
			           
	Begin   	  
	    OutText("ColouredRectangle created, color = "); OutText(Color);
	    OutImage;
        End of ColouredRectangle;

 
      	 Ref(Rectangle) Cr;            
	 Cr :- New ColouredRectangle(10, 20, "Green"); 
End;
Dieser Beispielcode stammt von Simula - 50 years of OOP. Wie du siehst, unterscheidet sich Java gar nicht so sehr von seiner Großelternsprache :) Das liegt daran, dass Simulas Auftreten die Geburt eines neuen Paradigmas bedeutete: objektorientierte Programmierung. Die englischsprachige Wikipedia definiert OOP wie folgt: „Objektorientierte Programmierung (OOP) ist ein Programmierparadigma, das auf dem Konzept von „Objekten“ basiert, die Daten in Form von Feldern (oft als Attribute bezeichnet) und Code in Form von Prozeduren (oft als Methoden bezeichnet) enthalten können.“ Ich finde diese Definition wirklich toll. Es ist noch gar nicht lange her, dass du angefangen hast, Java zu lernen, aber diese Definition enthält wahrscheinlich keine die unbekannten Begriffe :) Heute ist OOP die gängigste Programmiermethode. Zusätzlich zu Java werden OOP-Prinzipien in vielen weiteren populären Programmiersprachen verwendet, von denen du vielleicht schon gehört hast. Zum Beispiel C++ (wird aktiv in der Spieleentwicklung verwendet), Objective-C und Swift (wird verwendet, um Programme für Apple-Geräte zu schreiben), Python (am populärsten im Bereich Machine Learning), PHP (eine der populärsten Webentwicklungssprachen), JavaScript (es ist leichter zu sagen, wofür es nicht verwendet wird) und viele andere. Also, was sind denn eigentlich die „Prinzipien“ der OOP? Wir werden es dir im Detail erzählen.

Prinzipien der OOP

Dies ist das Fundament des Fundaments. Die 4 Grundpfeiler, die zusammen das Paradigma der objektorientierten Programmierung bilden. Sie zu verstehen ist unerlässlich, wenn du ein erfolgreicher Programmierer werden willst.

Prinzip 1. Vererbung

Gute Neuigkeiten: Du kennst bereits einige der Prinzipien der OOP! :) Wir sind im Kurs schon ein paar Mal auf die Vererbung gestoßen, und wir haben es sogar geschafft, sie zu nutzen. Vererbung ist ein Mechanismus, mit dem man eine neue Klasse basierend auf einer schon vorhandenen (Eltern-)Klasse beschreiben kann. Bei diesem Vorgang übernimmt die neue Klasse die Eigenschaften und Funktionen der Elternklasse. Was ist Vererbung und welche Vorteile bringt sie? Vor allem die Wiederverwendung von Code. Die in den Elternklassen deklarierten Felder und Methoden können in den Unterklassen verwendet werden. Wenn alle Autotypen 10 Felder gemeinsam und 5 identische Methoden haben, verschiebt man sie einfach in eine Elternklasse Car. Dann kannst du sie ohne Probleme in den Unterklassen verwenden. Handfeste Vorteile: sowohl quantitative (weniger Code) als auch qualitative (Klassen werden viel einfacher). Außerdem ist die Vererbung sehr flexibel – du kannst zusätzliche Funktionen schreiben, die den Unterklassen fehlen (einige Felder oder Verhaltensweisen, die spezifisch für eine bestimmte Klasse sind). Wie im wirklichen Leben sind wir alle unseren Eltern ein bisschen ähnlich, aber auch irgendwie anders als sie :)

Prinzip 2. Abstraktion

Dies ist ein sehr einfaches Prinzip. Abstraktion bedeutet, die wesentlichen, bedeutsamsten Eigenschaften von etwas zu identifizieren, während man gleichzeitig alles Nebensächliche und Unbedeutende verwirft. Es ist nicht nötig, das Rad neu zu erfinden. Erinnern wir uns an ein Beispiel aus einer alten Lektion über Klassen. Nehmen wir an, wir erstellen ein Ablagesystem für Firmenangestellte. Um „Mitarbeiter“-Objekte zu erstellen, haben wir eine Klasse Employee geschrieben. Welche Eigenschaften sind wichtig, um sie in der Firmenablage zu beschreiben? Name, Geburtsdatum, Sozialversicherungsnummer und Mitarbeiter-ID. Aber es ist unwahrscheinlich, dass wir die Größe, Augen- oder Haarfarbe des Angestellten für diese Art von Unterlagen benötigen. Das Unternehmen hat keinen Bedarf an solchen Informationen über einen Angestellten. Also deklarieren wir in der Klasse Employee die folgenden Variablen: String name, <int age, int socialSecurityNumber und int employeeId. Und wir abstrahieren von unnötigen Informationen wie die Augenfarbe. Wenn wir jedoch ein Ablagesystem für eine Modelagentur erstellen, ändert sich die Situation dramatisch. Die Größe, Augenfarbe und Haarfarbe sind wichtige Eigenschaften eines Models, aber ihre Sozialversicherungsnummer ist uns völlig egal. Also deklarieren wir in der Klasse Model die folgenden Variablen: String height, String hair, String eyes.

Prinzip 3. Kapselung

Der sind wir schonmal begegnet. In Java bedeutet Kapselung die Möglichkeit, das Lesen und Ändern von Daten einzuschränken. Wie du sehen kannst, basiert der Begriff auf dem Wort „Kapsel“. Wir verwenden eine „Kapsel“, um einige wichtige Daten zu verbergen, von denen wir nicht möchten, dass sie von anderen geändert werden. Hier ist ein einfaches Beispiel aus dem wirklichen Leben. Du hast einen Vornamen und einen Nachnamen. Alle deine Freunde kennen sie. Aber sie haben nicht die Möglichkeit, deinen Vor- oder Nachnamen zu ändern. Man könnte sagen, dass der Prozess der Namensänderung durch das Justizsystem „gekapselt“ ist: du kannst deinen Nachnamen nur durch einen Justizbeamten ändern lassen, und nur du kannst es tun. Andere „Benutzer“ haben „Lesezugriff“ auf deinen Vor- und Nachnamen :) Ein weiteres anschauliches Beispiel ist Bargeld, das man zu Hause aufbewahrt. Es in der Mitte deines Zimmers offen liegen zu lassen, ist keine gute Idee. Jeder „Benutzer“ (Person, die zu dir nach Hause kommt) kann deinen Geldbetrag ändern, d.h. dein Geld nehmen. Du solltest es besser in einem Tresor einkapseln. Dann wäre der Zugang nur für dich und nur mit einem speziellen Code möglich. Offensichtliche Beispiele für die Kapselung, mit der du bereits gearbeitet hast, sind Zugangsmodifikatoren (private, public usw.), sowie Getter und Setter. Wenn du bei der Klasse Cat nicht das Feld age einkapselst, dann kann jeder schreiben:

Cat.age = -1000;
Wir verwenden Kapselung, um das Feld age mit einer Setter-Methode zu schützen, mit der wir sicherstellen können, dass das Alter nicht auf eine negative Zahl gesetzt werden kann.

Prinzip 4. Polymorphismus

Polymorphismus ist die Möglichkeit, mit verschiedenen Typen zu arbeiten, als ob sie derselbe Typ wären. Außerdem ist das Verhalten jedes Objekts je nach seinem Typ unterschiedlich. Klingt das kompliziert? Sehen wir uns das mal an. Nehmen wir ein einfaches Beispiel: Tiere. Erstelle die Klasse Animal mit einer einzigen speak()-Methode und zwei Unterklassen: Cat und Dog.

public class Animal {

   public void speak() {
      
       System.out.println("Hello!");
   }
}

public class Dog extends Animal {
  
   @Override
   public void speak() {
       System.out.println ("Woof-woof!");
   }
}

public class Cat extends Animal {

   @Override
   public void speak() {
       System.out.println("Meow!");
   }
}
Jetzt deklarieren wir eine Animal-Referenzvariable und weisen ihr ein Dog-Objekt zu.

public class Main {

   public static void main(String[] args) {

       Animal dog = new Dog();
       dog.speak();
   }
}
Welche Methode wird wohl aufgerufen? Animal.speak() oder Dog.speak()? Die Methode der Dog-Klasse wird aufgerufen: Wuff-wuff! Wir haben eine Animal-Referenz erstellt, aber das Objekt verhält sich wie ein Dog. Wenn nötig, könnten wir Objekte haben, die sich wie eine Katze, ein Pferd oder ein anderes Tier verhalten. Entscheidend ist, der allgemeineren Referenzvariablen Animal eine bestimmte Unterklasse zuzuweisen. Das leuchtet ein, denn alle Hunde sind Tiere. Das meinten wir, als wir gesagt haben, das Verhalten jedes Objekts ist je nach seinem Typ unterschiedlich. Wenn wir ein Cat-Objekt erstellen würden...

public static void main(String[] args) {

   Animal cat = new Cat();
   cat.speak();
}
würde die speak()-Methode „Miau!“ anzeigen. Aber was meinen wir damit, dass Polymorphismus die Möglichkeit ist, mit verschiedenen Typen zu arbeiten, als ob sie derselbe Typ wären? Das ist auch ziemlich unkompliziert. Stellen wir uns vor, dass wir einen Tierpflegesalon erstellen. Unser Pflegesalon sollte in der Lage sein, jedem beliebigen Tier einen Haarschnitt zu verpassen, also erstellen wir eine trim()-Methode mit einem Animal-Parameter (das Tier, das einen Haarschnitt bekommt).

public class AnimalBarbershop {

   public void trim(Animal animal) {

       System.out.println("The haircut is done!"); 
   }
}
Jetzt können wir Cat- und Dog-Objekte an die trim()-Methode übergeben!

public static void main(String[] args) {

   Cat cat = new Cat();
   Dog dog = new Dog();

   AnimalBarbershop barbershop = new AnimalBarbershop();

   barbershop.trim(cat);
   barbershop.trim(dog);
}
Und das heißt folgendes: Die Klasse PetGroomingSalon interagiert mit den Typen Cat und Dog als wären sie derselbe Typ. Zugleich haben Cat und Dog unterschiedliche Verhaltensweisen, sie geben z.B. unterschiedliche Laute von sich.

Warum brauchen wir OOP?

Warum hat sich OOP überhaupt als neues Programmierparadigma entwickelt? Programmierer hatten funktionierende Werkzeuge, wie zum Beispiel prozedurale Sprachen. Was hat sie dazu gebracht, etwas grundlegend Neues zu erfinden? In erster Linie die Komplexität der Aufgaben, mit denen sie konfrontiert waren. Wenn vor 60 Jahren die Aufgabe eines Programmierers lautete: „Werte irgendeinen mathematischen Ausdruck aus“, so könnte sie heute lauten: „Implementiere 7 verschiedene Enden für das Spiel S.T.A.L.K.E.R., abhängig von den Kombinationen der Entscheidungen des Spielers an den Punkten A, B, C, D, E und F im Spiel.“ Du siehst also, dass die Aufgaben in den letzten Jahrzehnten offensichtlich komplizierter geworden sind. Infolgedessen sind auch die Datentypen komplizierter geworden. Dies ist ein weiterer Grund, weshalb OOP entstanden ist. Ein mathematischer Ausdruck kann leicht mit gewöhnlichen primitiven Datentypen ausgewertet werden. Dafür braucht man keine Objekte. Aber die Aufgabe mit den Spielenden wäre ohne die Verwendung von eigenen Klassen kaum zu beschreiben. Allerdings lässt sich die Aufgabe recht einfach mit Klassen und Objekten beschreiben. Offensichtlich brauchen wir mehrere Klassen: Game, Stalker, Ending, PlayerDecision, GameEvent usw. Mit anderen Worten, auch ohne bereits mit der Lösung des Problems zu beginnen, können wir leicht eine Lösung im Kopf „skizzieren“. Die zunehmende Komplexität der Aufgaben zwang die Programmierer, sie in Teile zu zerlegen. Aber in der prozeduralen Programmierung ist das nicht so einfach umzusetzen. Oft war ein Programm wie ein Baum mit vielen Ästen, die alle möglichen Ausführungspfade darstellten. Abhängig von bestimmten Bedingungen wurde der eine oder andere Zweig des Programms ausgeführt. Für kleine Programme funktionierte das gut, aber es war sehr schwierig, ein großes Problem in Teile zu zerlegen. Dies war ein weiterer Grund für die Entstehung der OOP. Dieses neue Paradigma gab den Programmierern die Möglichkeit, ein Programm in ein Paket von „Modulen“ (Klassen) zu unterteilen, von denen jedes seinen eigenen Teil der Arbeit erledigt. Indem sie miteinander interagieren, vollbringen alle Objekte die Arbeit unseres Programms. Außerdem können wir unseren Code an anderer Stelle im Programm wiederverwenden, was ebenfalls eine Menge Zeit spart.
Dieser Beitrag ist auf Englisch verfügbar.
Read the English version of this article for an introduction to OOP principles. The principles of object oriented programming form a solid foundation for your future career.
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION