fiebig.schule

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.

  1. Ergänze die Klasse FigureChameleonColor im Package model.

    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;
        }
     
    }
  2. Ersetze bei der Instanziierung der Spielfiguren eine Spielfigur vom Typ Figure durch eine Spielfigur des Typs FigureChameleonColor. Tipp:

    💁 Hilfe

    Also z. B. passiveFigures[15] = new FigureChameleonColor(15, true, true, true);

  3. Ergänze am Ende der Methode nextStateder Klasse QuartoGame die 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);
            }
        }
    }
  4. Ersetze die Methode drawFigure in der Klasse FigureDrawer durch 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

  1. 👤 Teste, welcher der folgenden vier Aufrufe in der Methode main zu 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);
}
  1. 👤 Ändere die Zugriffsmodifikatoren in der Klasse Figure geeignet.

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.

  1. 👤 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.

  1. 👤 Ergänze eine Typkonvertierung (typecaset), damit der folgende Methodenaufruf der Methode methodA funktioniert.
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.

  1. 👤 Finde oder ergänze im Quartoprojekt Beispiele für die oben genannten Fachkonzepte.

Die drei Wale – warum auch immer – der Objektorientierung
Bildquelle: Ivan-Corporation: Object-Oriented-Programming-Postulates

🟧 Übung und Recherche

Teilbare URL erstellen

Abschnitte auswählen