Dies ist eine alte Version des Dokuments!
Bei der Benennung von Methoden sollte man sich an zwei grundsätzliche Konventionen halten:
Unsere Klasse bekommt zwei weitere Methoden, eine um den Roboter an seiner aktuellen Position zu zeichnen und eine um den Roboter um einen gewissen Winkel zu drehen.
class Robot { // Deklaration der Klasse Robot int dRobot = 50; //Der Durchmesser des Roboters in Pixel float direction = PI; //Die Richtung in die der Roboter schaut //(PI (links), da der Winkel in Bogenmaß angegeben wird) float posX = 100; //Die x-Position des Roboters in Pixel float posY = 100; //Die y-Position des Roboters in Pixel //Diese Methode zeichnet einen Roboter //an seiner aktuellen Position und Ausrichtung. void drawRobot(){ //"void" bedeutet dass es keinen Rückgabewert gibt // Zeichne einen Kreis an der Position des Roboters. ellipse(posX,posY,dRobot,dRobot); // Zeichne eine Linie welche die Orientierung des Roboters angibt. line(posX,posY,posX+cos(direction)*50, posY+sin(direction)*50); } //Die moveForward-Funktion verändert die Position so, wie es einen Schritt nach vorne entspricht. void moveForward(float distance){ posX = posX+cos(direction)*distance; // Innerhalb der Funktion kann direkt auf die Klassenvariablen posY = posY+sin(direction)*distance; // zugegriffen werden. (Sie sind im Objekt quasi "lokal") } //Diese Methode dreht den Roboter um einen gewissen Winkel //welcher von "winkelaenderung" vorgegeben wird. // Die Methode bekommt einen Übergabeparameter vom Typ "float". void turnRobot(float angle){ this. direction += angle; } }
Jetzt können wir die fertige Klasse verwenden. Um dies in Processing auf eine möglichst übersichtliche weise zu tun sollte ein neuer Tab geöffnet werden:
In diesem neuen Tab speichert ihr eure Klasse.
In diesem Abschnitt ist das Beispiel von oben nochmals aufgeführt in einer „best-practise“-Version. Hierbei ändern sich zwei wesentliche Dinge:
class Robot { // Deklaration der Klasse Robot /** Der Durchmesser des Roboters. */ int dRobot; /** Die Richtung in die der Roboter schaut. */ float winkel; /** Die x-Position des Roboters. */ float posX; /** Die y-Position des Roboters. */ float posY; /** * Der "default"-Konstruktor erstellt ein Roboter-Objekt mit Standardwerten für alle notwendigen Parameter. */ public Robot() { this.dRobot = 50; this.winkel = PI; this.posX = 100; this.posY = 100; } /** * Dieser Konstruktor erstellt ein Roboter-Objekt mit allen notwendigen Parametern, * entsprechend der Vorgabe durch die Eingabeparameter. */ public Robot(int dRobot, float winkel, float posX, float posY) { this.dRobot = dRobot; this.winkel = winkel; this.posX = posX; this.posY = posY; } /** * Diese Methode zeichnet einen Roboter an seiner aktuellen Position und Ausrichtung. */ void drawRobot(){ // Zeichne einen Kreis an der Position des Roboters. ellipse(posX,posY,dRobot,dRobot); // Zeichne eine Linie welche die Orientierung des Roboters angibt. line(posX,posY,posX+cos(winkel)*50, posY+sin(winkel)*50); } /** * Diese Methode bewegt einen Roboter ein kleines Stück in die Richtung in die er gerade schaut. */ void moveRobot(){ this.posX = this.posX+cos(this.winkel)*2; this.posY = this.posY+sin(this.winkel)*2; } /** * Diese Methode dreht den Roboter um einen gewissen Winkel welcher von "winkelaenderung" vorgegeben wird. */ void turnRobot(float winkelaenderung){ this.winkel = winkel + winkelaenderung; } }
Im Paradigma des Objektorientierten Programmierens werden Zugriffsmodifizierer verwendet um die Rechte anderer Objekte einzuschränken (Datenkapselung). Unter Java werden folgende Zugriffsmodifizierer verwendet:
Die Klasse selbst, innere Klassen | Klassen im selben Package | Unterklassen | Sonstige Klassen | |
---|---|---|---|---|
private | Ja | Nein | Nein | Nein |
(default) | Ja | Ja | Nein | Nein |
protected | Ja | Ja | Ja | Nein |
public | Ja | Ja | Ja | Ja |
Der Zugriffsmodifizierer private verhindert jeden Zugriff von außerhalb einer Klasse auf den entsprechenden Member. Üblicherweise werden Klassenvariablen auf diese Weise deklariert und können dann nur über sog. getter- und setter-Methoden verändert werden. Für dieses Vorgehen gibt es gute Gründe, siehe Kapselung.
Der Zugriffsmodifizierer (default) wird implizit verwendet, d.h. wenn kein anderer Zugriffsmodifizierer angegeben wird ist der Member (default) oder package private. Auf Member mit diesem Zugriffsmodifizierer kann nur innerhalb eines Package zugegriffen werden.
Wie ihr vielleicht bemerkt habt kommt Processing ganz ohne Zugriffsmodifizierer aus. Das liegt daran das der Processing-Sketch zusammen mit allen Tabs in einem Package liegt und daher (default) ausreicht um auf alle Member zugriff zu haben. Um es dem Programmieranfänger einfach zu machen müsst ihr nicht extra angeben das sich alles in einem Package befindet, das übernimmt der Processing-Compiler.
Der Modifizierer protected ist etwas freizügiger als (default). Auf solche Member können auch Subklassen zugreifen, sogar wenn sie in einem anderen Package liegen als der betroffene Member.
Protected wird im Zusammenhang mit API-Programmierung und Templates verwendet.
Mit public gestattet ihr allen Klassen zugriff auf den jeweiligen Member. Wird in der Regel bei wichtigen Methoden, Konstruktoren und Datentypen eingesetzt.
Das ist letztendlich Geschmacksache und kommt darauf an wie und wo du an Code arbeitest.
Felix sagt: „Hier im Kurs sind Zugriffsmodifizierer unnötig, KISS-Prinzip“.
Ein Java Programmierer würde sagen: „In einfachen Fällen reicht private für Variablen und public für Methoden, Konstruktoren und Datentypen. Es gilt die Faustregel - so streng wie möglich, so freizügig wie nötig“.
public class PointIn2D { private int x, y; // private Klassenvariablen public PointIn2D(int x, int y) { // Konstruktor, für alle nutzbar setX(x); setY(y); } public int getX() { // getter-Methode return x; } public int getY() { return y; } public void setX(int x) { // setter-Methode zum Ändern der Klassenvariable this.x = x; } public void setY(int y) { this.y = y; } }
In Java kann unter Vererbung eine Spezialisierung einer bestehenden Klasse verstanden werden. Wir unterscheiden dazu in Super- und Subklassen. Die Superklasse (oder Elternklasse) beinhaltet eher allgemeine Attribute und Methoden. Die Klasse „Stift“ könnte z.B. Attribute für Stiftlänge, Stiftfarbe, usw. enthalten. Die Subklasse bekommt von der Superklasse alle Attribute und Methoden vererbt, erweitert dieses Set aber um eigene Attribute und Methoden. Z.B. könnte die Subklasse „Kugelschreiber“ das Attribut Stift eingefahren/Stift ausgefahren hinzufügen und eine Methode die diesen Zustand verändert.
Eine ausführliche Beschreibung wie Vererbung funktioniert findet ihr hier: http://www.java-tutorial.org/vererbung.html