02 | Quarto Chamäleon
I'm a Quarto figure without conviction
I am a Quarto figure who doesn't know
How to sell a contradiction
You come and go, you come and go
(frei nach Culture Club)
Das Spiel Quarto soll erweitert werden: Chamäleon-Spielfiguren ändern bei jedem Spielerwechsel ihre Eigenschaften.
🟪 Analyse
👤 Erweitere dein Spiel nach den folgenden Vorgaben und spiele ein paar Runden.
-
Ergänze die Klasse
FigureChameleonColorim Packagemodel.package model; public class FigureChameleonColor extends Figure { private int round = 0; public FigureChameleonColor(int id, boolean circular, boolean filled, boolean small) { super(id, circular, filled, false, small); } public void setRound(int round) { this.round = round; } public boolean isWhite() { return round % 2 == 0; } } -
Ersetze bei der Instanziierung der Spielfiguren eine Spielfigur vom Typ
Figuredurch eine Spielfigur des TypsFigureChameleonColor. Tipp:💁 Hilfe
Also z. B.
passiveFigures[15] = new FigureChameleonColor(15, true, true, true); -
Ergänze am Ende der Methode
nextStateder KlasseQuartoGamedie Aktualisierung der Chamäleon-Figuren:// update chameleons for (int i = 0; i < figuresOnBoard.length; i++) { for (int j = 0; j < figuresOnBoard[i].length; j++) { if (figuresOnBoard[i][j] instanceof FigureChameleonColor) { ((FigureChameleonColor) figuresOnBoard[i][j]).setRound(playersTurn); } } } -
Ersetze die Methode
drawFigurein der KlasseFigureDrawerdurch die folgende Methode:public void drawFigure(Figure figure, boolean isActive, int x, int y) { float xPos, yPos; int size; p.rectMode(3); if(isActive) { xPos = activeBoard.calculateCenterPoint(x, y)[0]; yPos = activeBoard.calculateCenterPoint(x, y)[1]; } else { xPos = passiveBoard.calculateCenterPoint(x, y)[0]; yPos = passiveBoard.calculateCenterPoint(x, y)[1]; } if (figure.isWhite()) p.fill(255); else p.fill(0); if(figure.isSmall()) size = 30; else size = 55; if(figure instanceof FigureChameleonColor) { p.strokeWeight(3); p.stroke(160, 32, 240); } else { p.strokeWeight(1); p.stroke(0); } if(figure.isCircular()) p.circle(xPos, yPos, size); else p.square(xPos, yPos, size); if(!figure.isFilled()) { p.fill(92, 64, 42); if (figure.isCircular()) p.circle(xPos, yPos, (float)size/2); else p.square(xPos, yPos, (float)size/2); } p.rectMode(0); p.strokeWeight(1); p.stroke(0); }
🟦 Erweiterung
👤 Erweitere das Projekt um andere Chamäleon-Klassen.
🟩 Vererbung in der Objektorientierung
👤 Ergänze die Lückentexte.
Überblick
Implementierung in Java
Am Beispiel von FigureChameleonColor
🟨 Vererbung im Detail
Datenkapselung
- 👤 Teste, welcher der folgenden vier Aufrufe in der Methode
mainzu einem Fehler führt und korrigieren ihn mit Hilfe des Merkkastens unten.
public class Base1 {
private int x;
public void setX(int pX) {
x = pX;
}
}
class Derived1 extends Base1 {
private int y;
public void setY(int pY) {
y = pY;
}
static void main() {
Derived1 derived1 = new Derived1();
// Todo: Kommentiere die Zeilen nacheinander ein!
// derived1.setX(67);
// derived1.setY(67);
// derived1.x = 67;
// derived1.y = 67;
}
}
📝 Um die Datenkapselung in Java umzusetzen, stehen u. a. folgende Zugriffsmodifikatoren für Attribute und Methoden zur Verfügung.
| Zugriffsmodifikator | UML | Sichtbarkeitsbereich | |||
|---|---|---|---|---|---|
| Klasse | Package | Unterklasse | Überall sichtbar | ||
public |
+ | ✓ | ✓ | ✓ | ✓ |
protected |
# | ✓ | ✓ | ✓ | ✗ |
| „ohne“ | ~ | ✓ | ✓ | ✗ | ✗ |
private |
− | ✓ | ✗ | ✗ | ✗ |
Die Ergänzung der folgenden Methode in der Klasse FigureChameleonColor führt zu einer Fehlermeldung.
public void printStatus() {
System.out.println("Weiß: " + white + "\nGefüllt: " + filled + "\nKlein: " + small + "\nRunde: " + round);
}
- 👤 Ändere die Zugriffsmodifikatoren in der Klasse
Figuregeeignet.
Welche Methode wird aufgerufen?
📝 In der Unterklasse wird eine Methode überschreiben, wenn die Methode der Unterklasse die gleiche Signatur besitzt wie die zu überschreibende Methode der Oberklasse. Die Signatur einer Methode besteht aus ihrem Methodenbezeichner und den vorgesehenen Parametertypen in der Reihenfolge ihrer Deklaration. Die überschriebene Methode bleibt über das Schlüsselwort super erreichbar.
- 👤 Notiere, welche Reihenfolge der Ausgabe du erwartest und teste anschließend den Programmcode.
public class Base2 {
static void main () {
Base2 b = new Derived();
b.methodA();
}
public void methodA() {
System.out.print("1");
methodB();
}
public void methodB() {
System.out.print("2");
}
}
class Derived extends Base2 {
public void methodA() {
super.methodA();
System.out.print("3");
}
public void methodB() {
super.methodB();
System.out.print("4");
}
}
Ein Objekt kann einen statischen Typ und einen davon abweichenden dynamischen Typ haben. Im Beispiel unten ist der statische Typ (declared type) des Objekts myObject die Klasse Base3, dagegen ist der dynamische Typ (actual type) die Klasse Derived3. Obacht: Es können nur Methoden aufgerufen werden, die in der Klasse des deklarierten Typs implementiert sind.
- 👤 Ergänze eine Typkonvertierung (typecaset), damit der folgende Methodenaufruf der Methode
methodAfunktioniert.
public class Base3 {
static void main () {
Base3 myObject = new Derived3();
myObject.methodA();
}
}
class Derived3 extends Base3 {
public void methodA() {
System.out.print("A");
}
}
Fachkonzepte
📝 Subtyping ermöglicht die Verwendung eines Objekts einer Unterklasse, wenn ein Objekt seiner Oberklasse erwartet wird (z. B. bei einer Assoziation, einem Array usw.).
📝 Polymorphie als compile-time polymorphism beschreibt das Überladen von Methoden, d. h. mehrere Methoden mit dem gleichen Methodenbezeichner aber unterschiedlichen Signaturen existieren. (Dafür braucht man gar keine Unterklassen.)
📝 Polymorphie als runtime polymorphism beschreibt den Vorgang, dass bei überschriebenen Methoden von der Java-Laufzeitumgebung erst zur Laufzeit entschieden wird, welche Methode aufgerufen wird; ausschlaggebend ist der dynamische Typ des Objektes.
- 👤 Finde oder ergänze im Quartoprojekt Beispiele für die oben genannten Fachkonzepte.
🟧 Übung und Recherche
- Übung: Polymorphie auf CSAwesome
- Recherche: Diamond-Problem