Modellierung - Zustandsbasiert

Einführung in Zustandsautomaten

Bearbeite den Abschnitt zur Einführung in Zustandsautomaten unter inf-schule.de. Bearbeite die Programmieraufgaben mit Scratch wie angegeben oder mit Greenfoot.

Informiere Dich über Konstanten und Enum-Typen in Java. Inwiefern können sie hier hilfreich sein?

Aufgabe - Zeichenstift

Bearbeite den Abschnitt Fallstudie - Zeichenstift mit Scratch wie angegeben oder mit Greenfoot. (Achtung: In Greenfoot musst Du verhindern, dass beim Drücken einer Taste der Zustand evtl. mehrfach hin- und herwechselt)

Aufgabe - Feuer frei

Du sollst ein kleines Greenfoot-Spiel fertig programmieren, bei dem eine Mutter ihrem Kind Essen zuwirft. Je länger Du die Leertaste drückst, desto weiter wirft sie. Eine fertige Version des Spiels kannst Du Dir zum Testen herunterladen. Eine Vorlage zum Spiel, das die entsprechenden Grafiken und einige Teile der Implementierung enthält, kannst Du Dir ebenfalls herunterladen.

Das Problem bei der Implementierung ist: Es gibt in Greenfoot keine Methode, um das Loslassen einer Taste zu erkennen.

Überlege Dir wie zustandsbasierte Modellierung Dir hier helfen kann, zeichne ein Zustandsdiagramm und implementiere das System.

Übersicht zu UML-Zustandsdiagrammen

  • Zustände werden in abgerundeten Kästen dargestellt
  • Ein Zustand hat einen Namen und kann haben:
    • Eintrittsaktion: Wird beim Betreten eines Zustands ausgeführt. Diese wird mit dem reservierten Wort entry/... markiert.
    • Austrittsaktion: Wird beim Verlassen ausgeführt und mit exit/... markiert.
    • Aktivitäten: Werden während eines Zustands dauerhaft ausgeführt und mit do/... markiert.
    • interne Transitionen: Beliebige Ereignisse, die keinen Zustandsübergang bewirken, aber Aktionen auslösen können.Eintritts- und Austrittsaktionen werden nicht ausgeführt.
  • Transitionen bezeichnen die Übergänge zwischen Zuständen. Sie sind markiert mit dem Ereignis, das sie auslösen. Zusätzlich kann in eckigen Klammern eine Bedingung (engl. Sprechweise: guard) angegeben werden. Durch Schrägstrich getrennt kann eine Aktion angegeben werden, die beim Übergang ausgeführt wird.
  • Ein Zustandsdiagramm besitzt genau einen Startzustand, der durch einen ausgefüllten Kreis dargestellt wird.
  • Ein Zustandsdiagramm kann beliebig viele Endzustände besitzen. Diese werden durch einen ausgefüllten "Doppelkreis" dargestellt.

Aufgabe - Streuner

Als streunender Hund kann man viel erleben. Überlege Dir welche Zustände ein streunender Hund haben kann, und welche Ereignisse auftreten können. Stelle Deine Überlegungen als UML-Zustandsdiagramm dar.

Implementiere Dein System in Greenfoot.

Modellierung einer Ampel

Im oben dargestellten Screencast siehst Du eine vereinfachte Ampelsteuerung.

  • Betrachte den Film und zeichne ein passendes Zustandsdiagramm.
  • Du benötigst für die Implementierung Nebenläufigkeit. Eine Möglichkeit dies hier umzusetzen bieten z.B. die Klassen Timer und TimerTask. Seit Java 5 existiert mit der Klasse ScheduledThreadPoolExecutor noch eine weitere Alternative, die insbesondere durch Lambda-Ausdrücke interessant ist. Ein Beispiel für deren Anwendung siehst Du unten. Teste und vergleiche die beiden Varianten. Nutze die Dokumentation der Java-API, um die Beispiele zu verstehen.
  • Implementiere das Modell.

Timer-Beispiel

import java.util.*;

class PingPongTimer {

	Timer timer;

	public PingPongTimer() {
		timer = new Timer();
		ping();
	}

	private void ping() {
		System.out.println("Ping");
		timer.schedule(new TimerTask() {

			@Override
			public void run() {
				pong();
			}
		}, 2000);
	}

	private void pong() {
		System.out.println("Pong");
		timer.schedule(new TimerTask() {

			@Override
			public void run() {
				ping();
			}
		}, 2000);
	}

	public void anhalten() {
		System.out.println("Stop");
		timer.cancel();
	}

}

ScheduledThreadPoolExecutor-Beispiel

import java.util.concurrent.*;

class PingPongExecutor {

    ScheduledThreadPoolExecutor timer;

    public PingPongExecutor() {
        timer = new ScheduledThreadPoolExecutor(1);
        ping();
    }

    private void ping() {
        System.out.println("Ping");
        timer.schedule(() -> pong(), 2, TimeUnit.SECONDS);
    }

    private void pong() {
        System.out.println("Pong");
        timer.schedule(() -> ping(), 2, TimeUnit.SECONDS);
    }
    
    public void anhalten() {
        System.out.println("Stop");
        timer.shutdownNow();
    }

}