Objekte und Klassen in Processing: Unterschied zwischen den Versionen
(→Konstruktoraufruf) |
(→Objekte) |
||
Zeile 31: | Zeile 31: | ||
*Die Methoden implementieren das Verhalten der Objekte. | *Die Methoden implementieren das Verhalten der Objekte. | ||
− | |||
− | |||
Zeile 40: | Zeile 38: | ||
Instanzvariablen und Methoden haben wir bereits kennengelernt. Neu sind die sogenannten Konstruktoren. | Instanzvariablen und Methoden haben wir bereits kennengelernt. Neu sind die sogenannten Konstruktoren. | ||
− | |||
=== Konstruktor === | === Konstruktor === |
Version vom 20. Dezember 2015, 12:53 Uhr
Nachdem wir nun die meisten Grundkonzepte der Programmierung (Variablen, Bedingungen, Schleifen, Methoden) kennengelernt haben, wenden wir uns nun einer Denkweise zu, die eine andere Art der Strukturierung und Organisation von Programmen darstellt - der sogenannten objektorientierten Modellierung.
Unter Objektorientierung versteht man eine Modellierung komplexer Systeme, bei der ein System durch ein Zusammenspiel verschiedener Objekte beschrieben wird. Der Begriff Objekt ist dabei unscharf gefasst: ausschlaggebend an einem Objekt ist nur, dass ihm bestimmte Attribute (Eigenschaften) und Methoden zugeordnet sind und dass es in der Lage ist, von anderen Objekten Informationen zu empfangen beziehungsweise an diese zu senden. Objekte müssen dabei nicht gegenständlich (konkret) sein, sondern können auch mehr oder weniger abstrakt sein. Entscheidend dabei ist, dass das Grundkonzept der Objektorientierung (Objekte mit bestimmten Eigenschaften und Methoden) sinnvoll umgesetzt werden kann. Programmiertechnisch entspricht diesem Ansatz das Konzept der Klasse, in der Objekte aufgrund ähnlicher Eigenschaften zusammengefasst werden. Ein Objekt wird im Programmcode als Instanz einer Klasse definiert.
Objekte
Bisher haben wir in Processing Objekte mit Hilfe vordefinierter Methoden erzeugt. Die große Stärke einer objektorientierten Programmiersprache besteht darin, dass wir als Programmierer eigene Datentypen in Form von Klassen nach unseren Vorstellungen und Bedürfnissen erstellen können, wodurch das Verhalten unserer Objekte deutlich flexibler gestaltet werden kann. Eine Klasse beschreibt entsprechend den Aufbau eines komplexen Datentyps.
Beispiele für Objekte der Klasse Rechteck:
Wie wir bereits aus der 6.Klasse wissen, lassen sich diese Objekte der Klasse Rechteck auch in Form von Objektdiagrammen darstellen.
Diese Darstellung von Objekten beinhaltet neben dem Objektnamen, der nach einer Konvention immer klein geschrieben wird, die Attribute des Objekts und die jeweiligen Attributwerte. Sie definieren den Zustand des Objekts. Objekte mit den denselben Attributen sind Instanzen einer Klasse. Eine Klasse stellt einen Konstruktionsplan für bestimmte Objekte dar, der mit all seinen Informationen auch ohne diese Objekte existiert. Eine Klasse ist also keine Menge von Objekten!
Die Definition einer Klasse beinhaltet drei Bestandteile:
- Die Datenfelder bzw. Instanzvariablen speichern die Daten, die das jeweilge Objekt benutzt.
- Die Konstruktoren erlauben es, neue Objekte zu erzeugen und diese in einen bestimmten Anfangszustand zu versetzen.
- Die Methoden implementieren das Verhalten der Objekte.
Beispiel: Die Klasse Rechteck
Instanzvariablen und Methoden haben wir bereits kennengelernt. Neu sind die sogenannten Konstruktoren.
Konstruktor
Eine Klasse kann keinen, einen oder mehrere unterschiedliche Konstruktoren besitzen. Sie dienen dazu, ein neu gebildetes Objekt einer Klasse in einen definierten Anfangszustand zu versetzen. Welcher dies ist hängt davon ab, welcher Konstruktor bei der Objektbildung aufgerufen wird. Ein leerer (Standard-) Konstruktor muss nicht angegeben werden, er wird bei Fehlen von der JVM (Java Virtual Machine) automatisch erzeugt. Aus diesem Grund hatten wir in unseren bisherigen Aufgaben keinen expliziten Konstruktor.
Syntax:
nameDerKlasse(Parameter) {}
Beispiel: Konstruktoren der obigen Klasse Rechteck:
Rechteck() weist dem Rechteck standardmäßig Werte zu.
Rechteck(){ breite = 10; hoehe = 7; }
Wir erhalten bei Aufruf des Konstruktors ein Rechteck der Größe 10x7. Die restlichen Werte werden von der JVM auf einen internen Standardwert gesetzt.
Rechteck(breite, hoehe) gibt dem User die Möglichkeit, die Größe des Rechtecks selbst zu bestimmen.
Rechteck(int breite, int hoehe){ this.breite = breite; this.hoehe = hoehe; }
Hier werden nach Aufruf des Konstruktors den Instanzvariablen die entsprechenden Werte der Parameter zugewiesen. Das Schlüsselwort this liefert innerhalb eines Objekts immer eine Referenz auf das Objekt selbst, d.h. es steht in der bekannten Punktschreibweise an der Stelle des Objektnamens einfach das Wort this.
Rechteck(breite, hoehe, fuellfarbe) gibt dem User die Möglichkeit, neben der Größe des Rechtecks auch noch dessen Füllfarbe festzulegen.
Rechteck(int breite, int hoehe, color fuellfarbe){ this.breite = breite; this.hoehe = hoehe; this.fuellfarbe = fuellfarbe }
Konstruktoren können also mit unterschiedlichen Parameterlisten deklariert sein. Man spricht hier vom Überladen des Konstruktors.
Konstruktoraufruf
Neue Instanzen einer Klasse werden mit dem Operator new erzeugt.
Rechteck rechteck1 = new Rechteck(); Rechteck rechteck2 = new Rechteck(12, 8); Rechteck rechteck3 = new Rechteck(15, 4, color(255, 0, 0));
Die drei erzeugten Rechtecke sind vom Typ Rechteck; d.h. sie sind Instanzen der Klasse Rechteck.
- rechteck1 wird mit dem Standardkonstruktor erzeugt und hat die Größe 10x7.
- rechteck2 wird vom User auf die Größe 12x8 festgelegt
- rechteck3 bekommt vom User die Größe 15x4 und die Füllfarbe rot zugewiesen.
Hier sollte nun deutlich werden, dass das erzeugte Objekt eine Variable ist, die nach dem Plan der Klasse Rechteck aufgebaut ist. Erst wenn das Objekt erzeugt wurde, kann mittels Punktschreibweise auch auf die Eigenschaften des Objekts zugegriffen werden. Beispiel:
rechteck1.breite = 10; rechteck3.fuellfarbe = "rot"
Sehen wir uns nun ein Processing-Programm mit einer Klasse in Aktion an.
Zuerst die Klasse (Klassen immer in einen neuen Tab schreiben):
class Rechteck{ //Attribute int xPos; int yPos; int laenge; int breite; int linienbreite; //Farben können wir mit dem Datentyp color darstellen color linienfarbe = color(255, 0, 0); color fuellfarbe = color(255, 255, 0); //Konstruktoren Rechteck(){ xPos = 100; yPos = 100; laenge = 100; breite = 50; } Rechteck(int laenge, int breite, color fuellfarbe){ xPos = width/2; yPos = height/2; this.laenge = laenge; this.breite = breite; this.fuellfarbe = fuellfarbe; } //Methoden void display(){ stroke(linienfarbe); fill(fuellfarbe); rect(xPos, yPos, laenge, breite); } void move(int v){ xPos = xPos + v; if(xPos>width){xPos = 0; fuellfarbe = color(random(256), random(256), random(256));}; } }
Nun können wir innerhalb des (Haupt)-Programms auf den neuen Datentyp zugreifen:
Rechteck r1; Rechteck r2; void setup(){ size(500, 300); r1 = new Rechteck(100, 50, color(255,0, 0)); r2 = new Rechteck(100, 50, color(255, 255, 0)); } void draw(){ background(0); r1.display(); r1.move(2); r2.display(); r2.move(3); }
Aufgabe 1 ("UFO-Attack")
Wir wollen nun Bewegung in unsere UFOs aus Aufgabe 2 im letzten Kapitel bringen. Wir brauchen dazu eine Klasse Ufo, die das Erzeugen der UFO-Objekte ermöglicht. Sie beinhaltet neben dem Konstruktor eine Methode display() zum Darstellen der Objekte und eine Klasse move() zum Bewegen der UFOs. Der Konstruktor sollte dabei einen Parameter enthalten, mit dem die move()-Funktion die UFOs in unterschiedliche Richtungen lenkt. Im Hauptprogramm bauen wir unsere Ufo-Armee aus einzelnen UFOs zusammen. Es reichen dabei 3 bis 5 UFOs um den Eindruck eines ganzen Schwarms zu erzeugen.