Kapitel 1 Das Projekt Uhr (Observer-Muster, MVC-Muster) Seite 1



Ähnliche Dokumente
Kapitel 4 Das Projekt Digitaluhr Seite 1

Enigmail Konfiguration

Kapitel 3 Frames Seite 1

Lineargleichungssysteme: Additions-/ Subtraktionsverfahren

Das sogenannte Beamen ist auch in EEP möglich ohne das Zusatzprogramm Beamer. Zwar etwas umständlicher aber es funktioniert

Mediator 9 - Lernprogramm

Objektorientierte Programmierung

Einführung in die Programmierung

Wir arbeiten mit Zufallszahlen

1 Einleitung. Lernziele. automatische Antworten bei Abwesenheit senden. Einstellungen für automatische Antworten Lerndauer. 4 Minuten.

Informatik Kurs Simulation. Hilfe für den Consideo Modeler

Kapitel 4 Die Datenbank Kuchenbestellung Seite 1

Arbeiten mit UMLed und Delphi

Einführung in die Java- Programmierung

Anleitung über den Umgang mit Schildern

Anleitung für Autoren auf sv-bofsheim.de

Primzahlen und RSA-Verschlüsselung

Benutzer-Handbuch

Nicht kopieren. Der neue Report von: Stefan Ploberger. 1. Ausgabe 2003

EAP. Employee Administration Platform

Zwischenablage (Bilder, Texte,...)

Wie halte ich Ordnung auf meiner Festplatte?

AutoCAD Dienstprogramm zur Lizenzübertragung

Outlook. sysplus.ch outlook - mail-grundlagen Seite 1/8. Mail-Grundlagen. Posteingang

Zahlenwinkel: Forscherkarte 1. alleine. Zahlenwinkel: Forschertipp 1

Anleitung zum Einstellen eines Artikels als Autor

Professionelle Seminare im Bereich MS-Office

1. Einführung Erstellung einer Teillieferung Erstellung einer Teilrechnung 6

Diese Anleitung wurde erstellt von Niclas Lüchau und Daniel Scherer. Erste Anmeldung. Schritt 1: Anmeldung..2. Schritt 2: Passwort setzen 3

5 Projekt Bankverwaltung

Installation von Druckern auf dem ZOVAS-Notebook. 1. Der Drucker ist direkt mit dem Notebook verbunden

Facebook erstellen und Einstellungen

Anton Ochsenkühn. amac BUCH VERLAG. Ecxel für Mac. amac-buch Verlag

Photopaint - Linsen. (Speichere deine Arbeit von Anfang an regelmäßig unter dem Namen Linsen.cpt )

2A Basistechniken: Weitere Aufgaben

Der neue persönliche Bereich/die CommSy-Leiste

Binäre Bäume. 1. Allgemeines. 2. Funktionsweise. 2.1 Eintragen

Um die Patientenverwaltung von Sesam zu nutzen, muss man die Patienten natürlich zuerst in die Kartei eintragen.

1. Einführung. 2. Alternativen zu eigenen Auswertungen. 3. Erstellen eigener Tabellen-Auswertungen

Jederzeit Ordnung halten

Nina. bei der Hörgeräte-Akustikerin. Musterexemplar

Zählen von Objekten einer bestimmten Klasse

Das Festkomitee hat die Abi-Seite neu konzipiert, die nun auf einem (gemieteten) Share Point Server

Erstellen einer Collage. Zuerst ein leeres Dokument erzeugen, auf dem alle anderen Bilder zusammengefügt werden sollen (über [Datei] > [Neu])

2 Das Projekt Taschenrechner

Unperfekthaus-Tutorial: Wordpress

Erstellen von x-y-diagrammen in OpenOffice.calc

Handbuch B4000+ Preset Manager

Datenbanken Kapitel 2

Kurzanleitung RACE APP

Delegatesund Ereignisse

Bilder zum Upload verkleinern

TYPO3 Tipps und Tricks

Technische Dokumentation SilentStatistikTool

Java: Vererbung. Teil 3: super()

Fachgebiet Informationssysteme Prof. Dr.-Ing. N. Fuhr. Programmierung Prof. Dr.-Ing. Nobert Fuhr. Übungsblatt Nr. 6

Fotostammtisch-Schaumburg

Wie gestaltet man Online-Umfragen mit SurveyMonkey?

Handbuch Fischertechnik-Einzelteiltabelle V3.7.3

Zahlen auf einen Blick

1 Vom Problem zum Programm

Programme im Griff Was bringt Ihnen dieses Kapitel?

Anzeige von eingescannten Rechnungen

Kapitel 4 Tabellen Seite 1. Nun wirst du eine Tabelle erstellen und ein wenig über deren Aufbau lernen.

1.Unterschied: Die Übungen sind nicht von deinem Mathe-Lehrer...

HANDBUCH PHOENIX II - DOKUMENTENVERWALTUNG

Folge 18 - Vererbung

Punkt 1 bis 11: -Anmeldung bei Schlecker und 1-8 -Herunterladen der Software

Der große VideoClip- Wettbewerb von Media Markt.

Programmierkurs Java

Erweitertes Kalkulationsfenster

Das DAAD-PORTAL. Prozess der Antragstellung in dem SAPbasierten Bewerbungsportal des DAAD.

Erstellen einer GoTalk-Auflage

Internationales Altkatholisches Laienforum

Der Kalender im ipad

iphone- und ipad-praxis: Kalender optimal synchronisieren

Windows. Workshop Internet-Explorer: Arbeiten mit Favoriten, Teil 1

Ist Fernsehen schädlich für die eigene Meinung oder fördert es unabhängig zu denken?

Access [basics] Rechnen in Berichten. Beispieldatenbank. Datensatzweise berechnen. Berechnung im Textfeld. Reporting in Berichten Rechnen in Berichten

Erweiterung der Aufgabe. Die Notenberechnung soll nicht nur für einen Schüler, sondern für bis zu 35 Schüler gehen:

Fidbox App. Version 3.1. für ios und Android. Anforderungen für Android: Bluetooth 4 und Android Version 4.1 oder neuer

Wie kann ich meine Daten importieren? Wie kann ich meine Profile verwalten?

ecaros2 - Accountmanager

Matrix42. Use Case - Sicherung und Rücksicherung persönlicher Einstellungen über Personal Backup. Version September

Er musste so eingerichtet werden, dass das D-Laufwerk auf das E-Laufwerk gespiegelt

Gruppenrichtlinien und Softwareverteilung

Drei-Schichten-Architektur. Informatik B - Objektorientierte Programmierung in Java. Vorlesung 16: 3-Schichten-Architektur 1 Fachkonzept - GUI

Die druckfähige pdf-version ist zu laden von lernelesen.com/bedienungsanleitung.htm

Verwalten und Organisieren von Fotos,

AGROPLUS Buchhaltung. Daten-Server und Sicherheitskopie. Version vom b

Dreamweaver 8 Einführung

Anleitung zur Daten zur Datensicherung und Datenrücksicherung. Datensicherung

it Symbiose Software Installation 1 Installationsbeschreibung für alle Series 60 (S60) Geräte - im speziellen Nokia S60-3rd Edition Stand März 2007

1. Adressen für den Serienversand (Briefe Katalogdruck Werbung/Anfrage ) auswählen. Die Auswahl kann gespeichert werden.

Mandant in den einzelnen Anwendungen löschen

CMS.R. Bedienungsanleitung. Modul Cron. Copyright CMS.R Revision 1

GEVITAS Farben-Reaktionstest

Übungen zu Einführung in die Informatik: Programmierung und Software-Entwicklung: Lösungsvorschlag

S/W mit PhotoLine. Inhaltsverzeichnis. PhotoLine

Nutzung der Onleihe Schritt für Schritt

Transkript:

Kapitel 1 Das Projekt Uhr (Observer-Muster, MVC-Muster) Seite 1 1 Das Projekt Uhr Bemerkung: Das Projekt Uhr habe ich aus dem Lehrbuch Java lernen mit BlueJ von M. Kölling und D. Barnes übernommen und sie an meinen Unterricht angepasst. Die Entwurfsmuster werden beschrieben im Buch Entwurfsmuster von Kopf bis Fuß von Eric Freeman und Elisabeth Freeman. Die Gestaltungsmöglichkeiten einer grafischen Oberfläche mit Swing werden in The JFC Swing Tutorial, Second Edition von Kathy Walrath u.a. dargestellt. Dieses Projekt modelliert eine Uhr. Die grafische Oberfläche, also die Sicht auf die Uhr, besteht aus drei Teilen, nämlich der Steuerung, der Digitaldarstellung und der Analogdarstellung. Dahinter steckt natürlich ein Uhrenmodel, das diese Sichten steuert, also auf die Benutzereingaben reagiert und im Sekundentakt die Uhrzeit steuert. Abbildung 1.1: Elemente der Uhr Du wirst lernen, wie die Uhr im Sekundentakt die Uhrzeit anzeigt und wie diese drei Darstellungen mit dem Uhrenmodel zusammen arbeiten. Hierzu wirst du die Entwurfsmuster Observer-Muster und MVC-Muster (Model-View- Controller) eingeführt. 1.1 Erstellung eines Modells Zuerst musst du das Modell einer Uhr entwerfen.

Kapitel 1 Das Projekt Uhr (Observer-Muster, MVC-Muster) Seite 2 Die Digitaldarstellung gibt dir einen ersten Hinweis auf das Modell. Du kannst die Digitaldarstellung auffassen als zwei getrennte Anzeigen. Die erste Anzeige erstellt ein Ziffernpaar für die Stunden, die zweite ein Ziffernpaar für die Minuten. Die Ziffernpaar für die Stunde startet bei 0, wird jede Stunde um 1 erhöht, bis sie 12 erreicht und wieder auf 0 zurückspringt. Die Ziffernpaar für die Minute startet bei 0, wird jede Minute um 1 erhöht, bis sie 59 erreicht und wieder auf 0 zurückspringt. Abbildung 1.2: Modellierung der Uhr Du erkennst, dass die Aufgaben dieser beiden Ziffernpaare identisch sind. Diese Aufgaben werden in der Klasse Ziffern erledigt. Dazu benötigst du zwei Datenfelder: limit wert an dem die Anzeige wieder auf 0 zurück springt, das den aktuellen Anzeigewert beinhaltet. Abbildung 1.3: Objekte stunden und minuten der Klasse Ziffern public class Ziffern private int limit; private int wert; // Konstruktor und Methoden hier ausgelassen Abbildung 1.4: Datenfelder der Klasse Ziffern Den Rest wirst du später kennen lernen.

Kapitel 1 Das Projekt Uhr (Observer-Muster, MVC-Muster) Seite 3 Nun zur Klasse Uhr. Diese Klasse muss die beiden Ziffernpaare für die Stunden und für die Minuten enthalten. Du definierst nun in der Klasse Uhr zwei Datenfelder stunden und minuten vom Typ Ziffern. Du benutzt also die Klasse Ziffern als den Typ für die Datenfelder stunden und minuten. Der Typ eines Datenfelds legt also fest, welche Arten von Werten in dem Datenfeld gespeichert werden können. Wenn der Typ eine Klasse ist, kann das entsprechende Datenfeld Objekte dieser Klasse enthalten. public class Uhr private Ziffern stunden; private Ziffern minuten; // Konstruktor und Methoden hier ausgelassen Abbildung 1.5: Datenfelder der Klasse Uhr Abbildung 1.6: Objektdiagramm für die Uhr Beachte, dass du mit zwei Klassen arbeitest, das Objektdiagramm jedoch drei Objekte anzeigt. Du erzeugst nämlich von der Klasse Ziffern zwei Objekte. Um nun diese Anwendung zu starten, wird ein Objekt meineuhr der Klasse Uhr erzeugt. Dieses erzeugt automatisch zwei Objekte stunden und minuten der Klasse Ziffern. Bemerkung: Wenn eine Variable ein Objekt enthält, dann ist das Objekt nicht direkt in der Variablen selbst abgelegt, sondern die Variable enthält lediglich eine Referenz auf ein Objekt (eine Objektreferenz). In Abbildung 1.6 ist im Objektdiagramm die Variable durch ein weißes Feld symbolisiert und die Referenz durch einen Pfeil. Das Objekt, das referenziert wird, ist außerhalb des die Referenz haltenden Objekts gespeichert. Die Objekte sind durch die Objektreferenz miteinander verbunden.

Kapitel 1 Das Projekt Uhr (Observer-Muster, MVC-Muster) Seite 4 Abbildung 1.7: Klassen Uhr und Ziffern in BlueJ Das Modell der Uhr ist nun entworfen. Nun wirst du dich der Implementierung dieses Modells widmen. 1.2 Die Klasse Ziffern Was muss die Klasse Ziffern alles können? 1. Sie muss den aktuellen Anzeigewert liefern: gibwert() 2. Sie muss den Anzeigewert um 1 vergrößern. Wenn das limit erreicht ist, muss dieser Wert auf 0 zurückspringen: erhoehen() Bemerkungen: In den folgenden Implementierungen verzichte ich auf die Kommentare. Dadurch werden die Abbildungen kleiner. public class Ziffern private int limit;

Kapitel 1 Das Projekt Uhr (Observer-Muster, MVC-Muster) Seite 5 private int wert; public Ziffern(int limit) this.limit = limit; wert = 0; public int gibwert() return wert; public void erhoehen() wert = (wert + 1) % limit; Abbildung 1.8: Quelltext der Klasse Ziffern Übung 1.1: Erzeuge in BlueJ ein Projekt Uhr01. Implementiere die Klasse Ziffern. Schreibe zusätzlich ausreichende Kommentare. Untersuche ihre Methoden mit Hilfe des Inspektors. Formuliere schriftlich, was der Operator % berechnet. (Setze dazu den Parameter limit probeweise auf den Wert 5.) Du hast nun also eine Klasse erstellt, die Ziffer anzeigt. Erzeugst du ein Objekt dieser Klasse, dem du dem Konstruktor als Parameter limit den Wert 12 mitgibst, stellt dieses die Stunden dar, ein Objekt mit limit = 60 stellt die Minuten dar. 1.3 Die Klasse Uhr Was muss die Klasse Uhr alles können? 1. Sie muss die Zeitanzeige als String darstellen: aktualisiereanzeige() 2. Sie muss diesen String als Wert zurückliefern: gibuhrzeit() Auch hier werden später noch weitere Methoden eingefügt. public class Uhr private Ziffern stunden; private Ziffern minuten; public Uhr()

Kapitel 1 Das Projekt Uhr (Observer-Muster, MVC-Muster) Seite 6 stunden = new Ziffern(12); minuten = new Ziffern(60); public int gibstunde() return stunden.gibwert(); public int gibminute() return minuten.gibwert(); Abbildung 1.9: Quelltext der Klasse Uhr Im Konstruktor werden die beiden Objekte stunden und minuten vom Typ Ziffern erzeugt. Mit dem Operator new wird also ein neues Objekt der angegebenen Klasse Ziffern erzeugt und der Konstruktor dieser Klasse ausgeführt. Der Konstruktor der Klasse Ziffern public Ziffern(int limit) besitzt den formalen Parameter int limit. Deshalb müssen die new- Anweisungen, die diesen Konstruktor aufrufen, jeweils einen aktuellen Parameter vom Typ int übergeben: stunden = new Ziffern(12); minuten = new Ziffern(60); Wenn also ein Objekt der Klasse Uhr erzeugt wird, so wird der Konstruktor der Klasse Uhr ausgeführt und dieser erzeugt automatisch zwei Objekte der Klasse Ziffern. Damit wird die bereits in Abbildung 1.6 dargestellte Situation erreicht. Übung 1.2: Implementiere im Projekt Uhr01 die Klasse Uhr. Erzeuge ein Objekt der Klasse Uhr und teste ihre Methoden gibstunde() und gibminute(). Momentan liefert sie nur als Ergebnis 0.

Kapitel 1 Das Projekt Uhr (Observer-Muster, MVC-Muster) Seite 7 Abbildung 1.10: Klasse Uhr mit ihrer Methode gibminute() Nun musst du noch ein Taktsignal simulieren. In der realen Welt sollte dieses jede Minute von einem Quarz erzeugt werden. In deinem Modell wirst du dich selbst bemühen müssen. public void setzetaktsignal() minuten.erhoehen(); if(minuten.gibwert() == 0) stunden.erhoehen(); Abbildung 1.11: Quelltext der Methode setzetaktsignal() in der Klasse Uhr Übung 1.3: Füge die Methode setzetaktsignal() der Klasse Uhr hinzu und teste ihre Methoden live mit Hilfe des Inspektors.

Kapitel 1 Das Projekt Uhr (Observer-Muster, MVC-Muster) Seite 8 Abbildung 1.12: Untersuchung der Klasse Uhr mit Hilfe des Inspektors Eine weitere Möglichkeit, die Methoden live zu testen, stellt die Verwendung des Terminals dar. private void gibuhrzeit() System.out.println(gibStunde() + " : " + gibminute()); Abbildung 1.13: Methode gibuhrzeit() in der Klasse Uhr Wird diese Methode in der Methode setzetaktsignal() aufgerufen, so wird jede Erhöhung des Minutenwerts im Terminal angezeigt. Abbildung 1.14: Das Terminal zeigt die Erhöhung des Minutenwerts

Kapitel 1 Das Projekt Uhr (Observer-Muster, MVC-Muster) Seite 9 Die dritte Möglichkeit, deinen Quelltext zu überprüfen, ist die Verwendung des Debuggers. Du wirst im Laufe der Zeit ein Gefühl dafür bekommen, welche der Möglichkeiten der Überprüfung (Inspektor, Terminal, Debugger) für die entsprechende Situation die bessere ist. Übung 1.4: Implementiere die Methode gibuhrzeit(). Rufe diese an geeigneter Stelle in deinem Programm auf. Vergleiche dein Ergebnis mit der Abbildung 1.14! Übung 1.5: (Für Fortgeschrittene) Programmiere eine Uhr mit Stunden- Minuten- und Sekundenanzeige! 1.4 Einführung in das Observer-Muster Natürlich ist es äußerst unbefriedigend, dass du jedes Mal die Methode setzetaktsignal() aufrufen musst, um den Minutenwert zu erhöhen. Du wirst nun lernen, hierzu einen Taktgeber zu verwenden, der diesen Aufruf automatisch tätigt (in diesem Beispiel alle 1000 ms, also eigentlich wird der Sekundenwert erhöht). Dazu wird das Observer-Muster verwendet. In Entwurfsmuster von Kopf bis Fuß wird das Observer-Muster in sehr treffender Weise mit dem Abonnieren einer Zeitung verglichen: 1. Ein Verlag startet ein Geschäft und veröffentlicht Zeitungen. 2. Du abonnierst ein bestimmtes Produkt eines Herausgebers, und jedes Mal, wenn es eine neue Ausgabe gibt, wird diese dir geliefert. Solange du Abonnent bleibst, erhältst du neue Zeitungen. 3. Du kündigst das Abonnement, wenn du die Zeitung nicht mehr möchtest, und die Lieferung wird eingestellt. 4. Solange der Herausgeber sein Gewerbe betreibt, abonnieren Personen, Hotels, Fluggesellschaften und andere Unternehmen die Zeitung oder kündigen ihre Abonnements. Und im Grunde funktioniert das Observer-Muster genauso. In diesem Fall ist der Herausgeber der Taktgeber und die Abonnenten sind die Uhren (man nennt sie auch Beobachter).

Kapitel 1 Das Projekt Uhr (Observer-Muster, MVC-Muster) Seite 10 Abbildung 1.15: Das Observer-Muster Nur der Taktgeber allein weiß genau, wann eine Sekunde vorbei ist. Die Beobachter, also die Uhren-Objekte ralphuhr, corinnauhr und karinuhr, haben ein Abonnement beim Taktgeber. Das bedeutet, sie haben sich beim Taktgeber registriert, um Aktualisierungen zu erhalten, wenn also der Taktgeber meldet, dass wieder eine Sekunde vorbei ist. Das Uhren-Objekt christianuhr hat leider Pech gehabt. Da es kein Beobachter ist, wird es auch nicht informiert, wenn sich die Daten des Taktgebers ändern. Aber christianuhr kann dem Taktgeber sagen, dass es Beobachter werden möchte. Dazu lässt es sich beim Taktgeber registrieren und wird somit in die Liste der Beobachter-Objekte aufgenommen. Nun wartet christianuhr zusammen mit den anderen Uhren auf die nächste Benachrichtigung von Taktgeber, dass wieder eine Sekunde vorbei ist. Genauso gut kann nun ralphuhr darum bitten, als Beobachter entfernt zu werden. Der Taktgeber berücksichtigt diese Anfrage und entfernt ralphuhr aus seiner Liste der Beobachter. Alle Beobachter, außer ralphuhr, der nun nicht mehr der Beobachtermenge angehört, erhalten weitere Benachrichtigungen vom Taktgeber. Das Prinzip des Observer-Muster ist nun erklärt. Jetzt wirst du dieses Muster modellieren. Die Abbildung 1.16 zeigt die beiden Klassen Taktgeber und Uhr mit ihren für das Observer-Muster wichtigen Datenfeldern und Methoden.

Kapitel 1 Das Projekt Uhr (Observer-Muster, MVC-Muster) Seite 11 Abbildung 1.16: Die Klassen Taktgeber und Uhr Die Klasse Uhr besitzt also ein Taktgeber-Objekt. Somit kann jedes Uhren- Objekt nun den Taktgeber bitten, dass Taktgeber dieses Uhren-Objekt registriert und somit in seine Beobachterliste aufnimmt. Falls sich der Zustand von Taktgeber geändert hat, beispielsweise eine Sekunde ist wieder vergangen, so durchläuft Taktgeber nun seine Beobachterliste, um alle registrierten Beobachter zu benachrichtigen, dass eine weitere Sekunde verstrichen ist. Allen Beobachter wird also gesagt, dass sie einen Taktimpuls empfangen. Und diese Beobachter können nun damit machen, was sie wollen, hier beispielsweise die Methode setzetakt() aufrufen und somit den Minutenwert erhöhen. Falls nun ein Uhren-Objekt beschließt, kaputt zu gehen, dann will es nicht länger Beobachter sein. Es teilt dem Taktgeber mit, dass es entfernt werden will und wird somit von Taktgeber aus seiner Beobachterliste gestrichen. Ganz so einfach ist diese Sache jedoch nicht. Es gibt verschiedene Uhren, beispielsweise Digitaluhren oder Analoguhren, Armbanduhren oder Taschenuhren, Bahnhofsuhren, Kirchturmuhren, usw. Oder vielleicht willst du einmal DJ spielen und an den Taktgeber auch einen Rhythmus-Generator anschließen. Oder ein Arzt will einen Herzschrittmacher mit dem Taktgeber verbinden. Alle diese Geräte sehen ein bisschen anders aus, haben somit verschiedene Methoden und alle diese verschiedenen Geräte müssen von einer einzigen Beobachterliste verwaltet werden. Das Problem ist nun, dass diese Beobachterliste nur einen einzigen Typ sammeln kann. Jedoch gemeinsam ist allen diesen Geräten, dass sie über ihre Methode empfangeimpuls() davon unterrichtet werden, dass eine Sekunde wieder verstrichen ist. Dieses Problem wird mit Hilfe eines Interfaces gelöst. Jedes Gerät, das irgendwie den Takt benötigt, muss dieses Interface implementieren. public interface Taktbeobachter

Kapitel 1 Das Projekt Uhr (Observer-Muster, MVC-Muster) Seite 12 public void empfangetaktimpuls(); Abbildung 1.17: Quelltext des Interfaces Taktbeobachter Bemerkung: Methoden in einem Interface sind öffentlich, public ist also nicht notwendig! Betrachte ein Interface zunächst einmal als eine Vereinbarung, dass alle Klassen, die dieses Interface implementieren, auch die Methode empfangetaktimpuls() besitzen. Der Taktgeber kann nun also sicher sein, dass alle seine Beobachter auch seine Benachrichtigung erhalten und damit etwas anfangen können. Er muss nichts darüber wissen, was die einzelnen Beobachter nun damit anfangen. Die Uhr zeigt die neue Zeit an, der Rhythmus-Generator treibt die Tänzer an und der Herzschrittmacher rettet Leben. Weiterhin wird hier auch der Polymorphismus genutzt, indem auf ein Sypertyp programmiert wird, damit das tatsächliche Laufzeitobjekt nicht im Quelltext festgeschrieben werden muss. Der Taktgeber sammelt also in seiner Beobachterliste nur noch Supertypen Taktbeobachter, er muss also die tatsächlichen Objekttypen (Uhr, Rhythmus-Generator, Herzschrittmacher) nicht kennen. Somit können an den Taktgeber alle möglichen Geräte angeschlossen werden, wichtig ist nur, dass diese das Interface Taktbeobachter implementiert haben. Wird nun ein neuer Beobachter hinzugefügt, so muss der Taktgeber nicht mehr verändert werden. Taktgeber und Beobachter sind locker gebunden, sie können miteinander agieren, müssen aber nur wenige Kenntnisse voneinander besitzen. Bevor du das Observer-Muster implementierst, solltest du dir die Zusammenhänge an Hand des Klassendiagramms in Abbildung 1.18 klar machen.

Kapitel 1 Das Projekt Uhr (Observer-Muster, MVC-Muster) Seite 13 Abbildung 1.18: Klassendiagramm des Projekts Uhr02 Du erkennst die bereits bekannten Klassen Ziffern und Uhr. Durch den Pfeil dargestellt wird, dass die Klasse Uhr das Interface Taktbeobachter implementiert hat. Neu hinzugekommen ist die Klasse Taktgeber. Da der Taktgeber in seiner Beobachterliste nur Taktbeobachter aufnimmt, benutzt er ebenso das Interface Taktbeobachter. Damit die Uhr sich bei einem Taktgeber- Objekt als Beobachter registrieren lassen kann, benutzt die Uhr die Klasse Taktgeber. 1.5 Den Takt angeben Zunächst wird das Observer-Muster aus Abbildung 1.15 in das Modell des Taktgebers implementiert. Es wird eine ArrayList taktbeobachterliste erzeugt. Anschließend folgen die Methoden zum Registrieren, Entfernen und Benachrichtigen aller Beobachter. import javax.swing.timer; import java.awt.event.*; import java.util.arraylist; public class Taktgeber private ArrayList<Taktbeobachter> taktbeobachterliste; public Taktgeber() taktbeobachterliste = new ArrayList<Taktbeobachter>();

Kapitel 1 Das Projekt Uhr (Observer-Muster, MVC-Muster) Seite 14 public void registrierebeobachter(taktbeobachter b) taktbeobachterliste.add(b); public void entfernebeobachter(taktbeobachter b) int i = taktbeobachterliste.indexof(b); if (i >= 0) taktbeobachterliste.remove(i); public void benachrichtigetakteobachter() for (Taktbeobachter beobachter : taktbeobachterliste) beobachter.empfangetaktimpuls(); Abbildung 1.19: Methoden für das Observer-Muster in der Klasse Taktgeber Übung 1.6: Sichere dein bisheriges Projekt als Uhr02. Implementiere die Klasse Taktgeber aus Abbildung 1.19. Nun musst du dafür sorgen, dass alle 1000 ms die Uhr benachrichtigt wird, den Minutenwert zu erhöhen. Allerdings ist der Taktgeber lose mit der Uhr gekoppelt. Theoretisch könnte auch jede Sekunde der Rhythmus-Generator oder der Herzschrittmacher benachrichtigt werden Also sollte der Swing-Timer nur alle Sekunde seine Beobachter benachrichtigen, das diese irgendetwas tun sollten, was, da braucht der Taktgeber ja nicht wissen. timer = new Timer(1000, new ActionListener() public void actionperformed(actionevent e) benachrichtigetakteobachter(); ); Abbildung 1.20: Erzeugung des Swing-Timers im Konstruktor der Klasse Taktgeber Der Timer ruft also alle 1000 ms die Methode benachrichtigetaktbeobachter() auf. Diese durchläuft alle Beobachter aus der taktbeobachterliste und sagt diesen empfangetaktimpuls().

Kapitel 1 Das Projekt Uhr (Observer-Muster, MVC-Muster) Seite 15 Wer sind jetzt aber diese Taktbeobachter? Das Klassendiagramm in Abbildung 1.18 besagt, dass alle Klassen, die das Interface Taktbeobachter implementiert haben, diese Taktbeobachter sind. Erinnere dich, ein Interface kannst du betrachten als eine Vereinbarung, dass alle Klassen auch die im Interface vorgeschriebenen Methoden besitzen. public interface Taktbeobachter public void empfangetaktimpuls(); Abbildung 1.21: Quelltext des Interfaces Taktbeobachter Die Klasse Uhr implementiert jetzt dieses Interface. Nun muss sie auch die Methode empfangetaktimpuls() besitzen, sonst erfüllt sie ja nicht den Vertrag mit dem Interface. Und gemäß der Abbildung 1.16 benötigt sie das Datenfeld Taktgeber, um sich bei diesem als Taktbeobachter zu registrieren public class Uhr implements Taktbeobachter private Taktgeber taktgeber; private Ziffern stunden; private Ziffern minuten; public Uhr(Taktgeber taktgeber) this.taktgeber = taktgeber; taktgeber.registrierebeobachter((taktbeobachter)this); stunden = new Ziffern(12); minuten = new Ziffern(60); public void setzetaktsignal() //bereits vorhanden public int gibstunde() //bereits vorhanden public int gibminute() //bereits vorhanden

Kapitel 1 Das Projekt Uhr (Observer-Muster, MVC-Muster) Seite 16 public void empfangetaktimpuls() setzetaktsignal(); private void gibuhrzeit() //bereits vorhanden Abbildung 1.22: Zusätzlicher Quelltext in der Klasse Uhr Übung 1.7: Implementiere den Quelltext aus den Abbildungen 1.20, 1.21 und 1.22. Deine Uhr wird noch nicht funktionieren. Erzeuge jedoch ein Objekt der Klasse Taktgeber und anschließend ein Objekt der Klasse Uhr. Prüfe mit dem Inspektor, ob du in der Beobachterliste des Taktgebers die Uhr findest? Überlege mit Hilfe des Quelltexts, wie die Uhr in diese Beobachterliste aufgenommen wird. Abbildung 1.23: Taktgeber besitzt die Uhr als erstes Element in seiner Beobachterliste Nun musst du die Uhr nur noch in Gang setzen. Dazu gibt es bestimmte Timer- Methoden wie start() bzw. stop(). Um den Timer etwas universeller einzusetzen, wird auch noch die Methode setdelay() implementiert.

Kapitel 1 Das Projekt Uhr (Observer-Muster, MVC-Muster) Seite 17 public void starten() timer.start(); //voreingestellte Timermethode public void anhalten() timer.stop(); //voreingestellte Timermethode public void setzedauer(int dauer) timer.setdelay(dauer); //voreingestellte Timermethode Abbildung 1.24: Methoden des Timers in der Klasse Taktgeber Übung 1.8: Implementiere in der Klasse Taktgeber die in Abbildung 1.24 dargestellten Timer-Methoden. Teste nun dein Projekt Uhr02. Abbildung 1.25: Die Uhr läuft

Kapitel 1 Das Projekt Uhr (Observer-Muster, MVC-Muster) Seite 18 Nachdem die Uhr nun funktioniert, kannst du dich der grafischen Benutzeroberfläche widmen. Hierzu wirst du nun ein weiteres Programmiermuster kennen lernen, das so genannte MVC-Muster. 1.6 Einführung in das MVC-Muster Model-View-Controller (MVC, wörtlich etwa Modell-Präsentation-Steuerung ) bezeichnet ein Architekturmuster zur Aufteilung von Softwaresystemen in die drei Einheiten: Datenmodell (engl. Model), Präsentation (engl. View) und Programmsteuerung (engl. Controller). Abbildung 1.26: Das MVC-Muster Ziel des Musters ist ein flexibles Programmdesign, das eine spätere Änderung oder Erweiterung erleichtern und eine Wiederverwendbarkeit der einzelnen Komponenten ermöglichen soll. Als Model wird die Komponente bezeichnet, die die Datenstruktur der Anwendung definiert. Das Model speichert die Daten und somit den Zustand der Anwendung und stellt die Methoden zur Änderung der Daten zur Verfügung. Das Model kennt weder den View noch den Controller. Als View wird die Komponente bezeichnet, die die Daten des Models auf dem Bildschirm präsentiert, jedoch keine Programmlogik besitzt. Der Benutzer führt auf dem View die Aktionen aus, die durch den Controller an das Model weitergeleitet werden. Der View kennt das Model, ist dort registriert und kann dessen Zustand erfragen. Als Controller wird die Komponente bezeichnet, die die Ablaufsteuerung darstellt. Der Controller kennt die beiden anderen Komponenten, den View und das Model. Er reagiert auf die Interaktionen der Anwender in dem View und überprüft diese. Anschließend ruft er die jeweilige Methode des Models auf und verändert dessen Zustand.

Kapitel 1 Das Projekt Uhr (Observer-Muster, MVC-Muster) Seite 19 Abbildung 1.27: Beziehungen zwischen Model, View und Controller 1. Du als Beobachter interagierst mit dem View. Der View ist also deine Sicht auf das Model. Wenn du also irgendetwas mit dem View machst, beispielsweise auf den start-button klickst, teilt der View dem Controller mit, was du getan hast. Es ist dann Aufgabe des Controllers, entsprechende Steuerungsmaßnahmen zu ergreifen. 2. Der Controller fordert das Model auf, seinen Zustand zu ändern. Der Controller nimmt deine Aktionen an und interpretiert sie. Wenn du auf einen Button klickst, muss der Controller herausfinden, was das bedeutet und wie das Model auf Grund dieser Aktion beeinflusst werden muss. 3. Der Controller kann auch den View auffordern, seinen Zustand zu ändern. Wenn der Controller eine Aktion vom View erhält, muss er den View auf Grund dessen eventuell auffordern, sich zu ändern. Beispielsweise könnte der Controller bestimmte Buttons oder Menüpunkte in der grafischen Benutzeroberfläche aktivieren oder deaktivieren. 4. Das Model benachrichtigt den View, wenn sich sein Zustand geändert hat. Wenn sich am Model etwas ändert entweder auf Grund einer Aktion von dir (beispielsweise die Uhr stoppen) oder einer internen Veränderung (beispielsweise eine Minute ist vergangen) -, meldet das Model dem View, dass sich sein Zustand geändert hat.

Kapitel 1 Das Projekt Uhr (Observer-Muster, MVC-Muster) Seite 20 dass sich sein Zustand geändert hat. 5. Der View fragt das Model nach seinem Zustand. Der View erhält den Zustand, den er anzeigt, direkt vom Modell. Wird er beispielsweise vom Model benachrichtigt, dass eine neue Minute angefangen hat, fragt der View das Model nach der aktuellen Uhrzeit und zeigt diese an. Der View kann das Model auch nach dessen Zustand fragen, wenn er vom Controller aufgefordert wurde, die Ansicht zu verändern. Nun wirst du die drei Komponenten im Uhrenmodell zusammenbauen. Abbildung 1.28: Die Uhr im MVC-Muster Wenn du den Text aufmerksam gelesen hast, wirst du bemerkt haben, dass das Model den View benachrichtigt, dass sich der Minutenwert geändert hat, obwohl

Kapitel 1 Das Projekt Uhr (Observer-Muster, MVC-Muster) Seite 21 das Model weder den View noch den Controller kennt. Trotzdem zeigen alle drei Abbildungen einen Pfeil vom Model zum View. Der View besteht aus mehreren Fenstern. In Abbildung 1.28 sind die beiden Fenster SteuerungView und DigitalView dargestellt. Die Uhr kann aber auch in einem AnalogView wie in Abbildung 1.1 gezeigt werden. Du kannst dir noch weitere Darstellungsmöglichkeiten ausdenken. Um all diese verschiedenen Views zu verwalten, verwendet das Model das Observer-Muster. Es benötigt daher Methoden zur Registrierung von Objekten als Zeitbeobachter und Methoden zum Verschicken von Nachrichten an diese Zeitbeobachter. Das Model kennt also nur diese Zeitbeobachter. Das Observer- Muster verlangt, dass Zeitbeobachter ein Interface ist und dass alle Views, die die Uhrzeit benötigen, das Interface Zeitbeobachter implementieren. Somit kennt das Model nicht die Komponenten des Views, sondern die Zeitbeobachter. 1.7 MVC-Muster konkret 1.7.1 Die Klasse Uhr Die Uhr muss nun mehrere Views überwachen, in diesem Beispiel den DigitalView, den AnalogView und vielleicht später noch weitere Viewkomponenten, beispielsweise als Sanduhr, oder was sich Uhrenbauer sonst noch so einfallen lassen. Abbildung 1.29: Das Observer-Muster Deswegen sammelt die Klasse Uhr all diese Beobachter-Objekte in eine Zeitbeobachterliste. Zusätzlich erhält die Klasse Uhr auch Methoden, um diese Zeitbeobachter-Objekte zu registrieren, zu entfernen und zu benachrichtigen.

Kapitel 1 Das Projekt Uhr (Observer-Muster, MVC-Muster) Seite 22 Dahinter steckt also das Observer-Muster. Der Quelltext der Klasse Uhr wird nun so angepasst, dass diese dem Observer-Muster genügt. Übung 1.9: Studiere noch einmal das Kapitel 1.4 Kurze Einführung in das Observer-Muster. Informiere dich insbesondere, wie 1. die Beobachter in einer ArrayList gesammelt werden, 2. wozu das Interface (damals Taktbeobachter, jetzt Zeitbeobachter) benötigt wird, 3. wie die Beobachter benachrichtigt werden. Vergleiche hierzu die Klassen Taktgeber und Uhr aus der Abbildung 1.16 mit den Klassen Uhr und DigitalView aus der Abbildung 1.30. Abbildung 1.30: Die Klassen Uhr und DigitalView In der Kasse Uhr muss du also eine zeitbeobachterliste erzeugen und die Methoden registrierebeobachter(), entfernebeobachter() und benachrichtigebeobachter() implementieren. import java.util.arraylist; public class Uhr implements Taktbeobachter //Datenfelder //bereits vorhanden //beobachtende Objekte, die von Uhr benachrichtigt werden private ArrayList<Zeitbeobachter> zeitbeobachterliste; public Uhr(Taktgeber taktgeber) zeitbeobachterliste = new ArrayList<Zeitbeobachter>();

Kapitel 1 Das Projekt Uhr (Observer-Muster, MVC-Muster) Seite 23 //bereits vorhanden public void setzetaktsignal() //bereits vorhanden public int gibstunde() //bereits vorhanden public int gibminute() //bereits vorhanden public void empfangetaktimpuls() //bereits vorhanden public void registrierebeobachter(zeitbeobachter b) zeitbeobachterliste.add(b); public void entfernebeobachter(zeitbeobachter b) int i = zeitbeobachterliste.indexof(b); if (i >= 0) zeitbeobachterliste.remove(i); public void benachrichtigezeitbeobachter() for (Zeitbeobachter beobachter : zeitbeobachterliste) beobachter.empfangeuhrzeit(); private void gibuhrzeit() //bereits vorhanden Abbildung 1.31: Quelltext der Klasse Uhr erweitert um das Observer-Muster

Kapitel 1 Das Projekt Uhr (Observer-Muster, MVC-Muster) Seite 24 Übung 1.10: Sichere dein bisheriges Projekt als Uhr03a. Implementiere die Klasse Uhr aus Abbildung 1.31. Übung 1.11: Überlege, in welcher Methode der Klasse Uhr die Methode benachrichtigezeitbeobachter() aufgerufen werden muss. (Hinweis: Hier wird auch die Uhrzeit im Terminal ausgegeben.) 1.7.2 Das Interface Zeitbeobachter Wie du in Übung 1.9 gelernt hast, benötigst du für die Menge der Beobachter- Objekte das Interface Zeitbeobachter, das all diese Beobachter-Objekte implementieren müssen. Dieses Interface wird analog dem Interface Taktbeobachter gestaltet. Erinnere dich, ein Interface kannst du betrachten als eine Vereinbarung, dass alle Klassen auch die im Interface vorgeschriebenen Methoden besitzen. public interface Zeitbeobachter public void empfangeuhrzeit(); Abbildung 1.32: Quelltext des Interfaces Zeitbeobachter Bemerkung: Die Methoden in einem Interface sind automatisch öffentlich, public ist also nicht notwendig! Übung 1.12: Implementiere das Interface Zeitbeobachter im Projekt Uhr03a. 1.7.3 Die Klasse DigitalView Bemerkung: Das Programmieren einer grafischen Benutzeroberfläche ist hier nicht das Thema. Die Gestaltungsmöglichkeiten mit Swing werden in The JFC Swing Tutorial, Second Edition von Kathy Walrtath, in Handbuch der Java- Programmierung von Guido Krüger, u. a oder in ähnlichen Büchern beschrieben.

Kapitel 1 Das Projekt Uhr (Observer-Muster, MVC-Muster) Seite 25 Abbildung 1.33: Grafische Oberfläche der digitalen Anzeige Übung 1.13: Hole vom Schulserver (oder von meiner Homepage) das Projekt DigitalGUI. Füge mit Hilfe von Add Class from File die Klasse DigitalView in dein Projekt Uhr03a ein. Studiere den Quelltext der Klasse DigitalView. Suche die Komponenten zeitl und zeittf. Überlege, wie diese Komponenten in das Fenster eingebaut wurden. Wie in Abbildung 1.30 bereits dargestellt, besitzt die Klasse DigitalView also ein Uhr-Objekt. Somit kann das DigitalView-Objekt nun die Uhr bitten, dass Uhr dieses DigitalView-Objekt registriert und somit in seine Beobachterliste aufnimmt. Falls sich der Zustand von Uhr geändert hat, beispielsweise eine Sekunde ist wieder vergangen, so durchläuft Uhr nun seine Beobachterliste, um alle registrierten Beobachter zu benachrichtigen, dass eine weitere Sekunde verstrichen ist. Allen Beobachter wird also gesagt, dass sie eine neue Uhrzeit empfangen. Und diese Beobachter können nun damit machen, was sie wollen, hier beispielsweise die Stunden und die Minuten in digitaler Form in ein Textfeld schreiben. Übung 1.14: Die Klasse DigitalView soll nun das Interface Zeitbeobachter implementieren und ein Datenfeld uhr erhalten. Im Konstruktor soll DigitalView sich bei der Uhr als Zeitbeobachter registrieren. Zuletzt muss DigitalView noch die im Interface Zeitbeobachter vertraglich festgelegte (noch leere) Methode empfangeuhrzeit() erhalten. Vergleiche hierzu auch die Abbildung 1.30. Hat sich also nun der Zustand der Uhr (des Models) geändert, so durchläuft die Uhr ihre Liste aller Zeitbeobachter (und somit auch alle Views) und

Kapitel 1 Das Projekt Uhr (Observer-Muster, MVC-Muster) Seite 26 benachrichtigt diese, dass eine neue Uhrzeit zum Empfang vorliegt. Die Views fragen nun beim Model nach der aktuellen Stunde und der aktuellen Minute. Übung 1.15: Betrachte die Abbildungen 1.27 und 1.28 und suche die oben beschriebenen Datenflüsse. Der aktuelle Stundenwert und der aktuelle Minutenwert werden von dem DigitalView zu einer Digitalanzeige (z.b. 10 : 15) zusammengesetzt und in das entsprechende Textfeld geschrieben. public void empfangeuhrzeit() String digitalanzeige = erstelledigitalanzeige(); zeittf.settext(digitalanzeige); private String erstelledigitalanzeige() String stundenanzeige, minutenanzeige; int stunde = uhr.gibstunde(); if (stunde < 10) stundenanzeige = "0" + stunde; else stundenanzeige = "" + stunde; int minute = uhr.gibminute(); if (minute < 10) minutenanzeige = "0" + minute; else minutenanzeige = "" + minute; return stundenanzeige + " : " + minutenanzeige; Abbildung 1.34: Die Methoden empfangeuhrzeit() und erstelledigitalanzeige() in der Klasse DigitalView Übung 1.16: Implementiere die beiden Methoden empfangeuhrzeit() und erstelledigitalanzeige() in der Klasse Digitaluhr.

Kapitel 1 Das Projekt Uhr (Observer-Muster, MVC-Muster) Seite 27 Teste nun dein Projekt Uhr03a. Erzeuge zuerst einen Taktgeber, dann eine Uhr und zum Schluss einen DigitalView. Rufe nun die Methode starten() und etwas später die Methode anhalten() im Taktgeber-Objekt auf. Abbildung 1.35: Klassendiagramm des Projekts Uhr03a In der Übung 1.16 wirst du festgestellt haben, dass du zuerst ein Taktgeber- Objekt erzeugen musst. Damit die Uhr sich als Beobachter beim Taktgeber registrieren lassen kann, muss also der Uhr dieses Taktgeber-Objekt als Parameter übergeben werden. Und damit sich der DigitalView als Beobachter bei der Uhr registrieren lassen kann, muss das DigitalView-Objekt die Uhr als Parameter übergeben werden. Du hast also das Observer-Muster zweimal angewendet, zwischen Taktgeber und Uhr und zwischen Uhr und DigitalView. 1.7.4 Die Klasse SteuerungView Die grafsche Oberfläche zeigt zwar nun die Uhrzeit, aber ist noch nicht für Benutzereingaben vorbereitet. Hierzu wird der View erweitert durch ein neues Fenster, dem SteuerungView. Zuerst interessieren nur die drei Button start, stopp und beenden. Hiermit wird die Uhr vom Benutzer gesteuert. Die Uhr kann gestartet werden und vom View wird die aktuelle Uhrzeit abgefragt. Analog kann mit Hilfe der beiden anderen Buttons die Uhr gestoppt werden oder die Anwendung geschlossen werden.

Kapitel 1 Das Projekt Uhr (Observer-Muster, MVC-Muster) Seite 28 Abbildung 1.36: Die grafische Oberfläche zur Steuerung der Uhr Übung 1.17: Sichere dein bisheriges Projekt als Uhr03b. Hole vom Schulserver (oder von meiner Homepage) das Projekt SteuerungGUI. Füge mit Hilfe von Add Class from File die Klasse SteuerunglView in dein Projekt Uhr03b ein. Studiere den Quelltext der Klasse SteuerungView. a) Suche die Komponenten start, stopp und beenden. b) Suche die Komponenten digital und analog. Informiere dich, wieso Radiobuttons in einer ButtonGroup zusammengefasst werden. c) Überlege, wie diese Komponenten in das Fenster eingebaut wurden. Der Benutzer hat also nun den Button start gedrückt. Der SteuerungView delegiert diese Benutzeraktion an den Controller. Der Controller ist das einzige Objekt, das weiß, wie man mit den Aktionen des Benutzers umgeht. Der Controller entscheidet, a) ob er dem Model mitteilen soll, dass es seinen Zustand ändern soll, b) ob er dem View mitteilen soll, dass er seine Anzeige ändern soll. Übung 1.18: Betrachte die Abbildungen 1.27 und 1.28 und suche die oben beschriebenen Datenflüsse. Die Benutzeraktionen werden vom SteuerungView direkt an den Controller weitergeleitet. Die Klasse SteuerungView muss deshalb ein Datenfeld controller erhalten. Der Konstruktor erhält als Parameter somit ein Controller-Objekt, das in dem Datenfeld controller gehalten wird

Kapitel 1 Das Projekt Uhr (Observer-Muster, MVC-Muster) Seite 29 private Controller controller; public SteuerungView(Controller controller) this.controller = controller; erzeugefenster(); Abbildung 1.37: Datenfeld und Konstruktor der Klasse SteuerungView Klickt der Benutzer nun auf den Button start, so wird dies dem Controller mitgeteilt. private void startaction() controller.start(); private void stoppaction() controller.stopp(); Abbildung 1.38: Mitteilungen von Benutzereingaben an den Controller in der Klasse SteuerungView Übung 1.19: Implementiere den in den Abbildungen 1.37 und 1.38 dargestellten Quelltext. Suche in den Abbildungen 1.27 und 1.28 den hier programmierten Schritt. 1.7.5 Die Klasse Controller Jetzt musst du dich noch um den Controller kümmern. Eine der Aufgabe ndes Controllers ist, auf Grund der Benutzeraktion im View zu entscheiden, welche Daten im Model geändert werden müssen. (Später wird der Controller auch noch den View ändern.) Der Controller darf jedoch nicht die Daten selbst manipulieren, dies muss das Model machen. public class Controller Uhr uhr; Taktgeber taktgeber;

Kapitel 1 Das Projekt Uhr (Observer-Muster, MVC-Muster) Seite 30 SteuerungView steuerungview; DigitalView digitalview; public Controller(Taktgeber taktgeber, Uhr uhr) this.taktgeber = taktgeber; this.uhr = uhr; steuerungview = new SteuerungView(this); digitalview = new DigitalView(uhr); public void start() taktgeber.starten(); public void stopp() taktgeber.anhalten(); Abbildung 1.39: Quelltext der Klasse Controller Wie bereits in der Einführung in das MVC-Muster beschrieben, kennt der Controller die beiden anderen Komponenten, den View und das Model. Er ist also dasjenige Objekt, das alles zusammenhält. Deswegen erhält der Konstruktor das Model (die Uhr) als Argument und erzeugt den View. Der View besteht jetzt bereits schon aus zwei Teilen, 1. dem SteuerungsView, der den Controller benötigt, der ja die Benutzereingaben delegierien muss, 2. dem DigitalView, der das Model (die Uhr) benötigt, um dessen Zustand abzufragen. Hat der Anwender in der grafischen Benutzeroberfläche auf start gedrückt, startet der Controller den Taktgeber, der wiederum den Minutenwert in der Uhr erhöht. Der DigitalView (eigentlich alle Zeitbeobachter) wird von der Uhr benachrichtigt, dass sich ihr Zustand (neue Uhrzeit) geändert hat. Der DigitalView fragt bei der Uhr nach dem aktuellen Minuten- und Stundenwert, erstellt daraus eine Digitalanzeige und schreibt diese in das entsprechende Textfeld.

Kapitel 1 Das Projekt Uhr (Observer-Muster, MVC-Muster) Seite 31 Abbildung 1.40: Klassendiagramm des Projekts Uhr03b Übung 1.20: Versuche die oben beschriebenen Datenflüsse im Klassendiagramm des Projekt Uhr03b nachzuvollziehen. Vergleiche deine Gedanken auch mit den Beziehungen zwischen Model, View und Controller in den Abbildungen 1.27 und 1.28. Übung 1.21: Implementiere die Klasse Controller in deinem Projekt Uhr03b. Teste dein Projekt, indem du nacheinander ein Taktgeber-Objekt, dann ein Uhr-Objekt und zum Schluss ein Controller-Objekt erzeugst. Bemerkung: Der View und der Controller stellen das Strategy-Muster dar. Der View ist nur für die Sicht zuständig, die Entscheidungen über sein Verhalten delegiert er an den Controller. Der Controller ist somit das Verhalten (die Strategie) des Views. Wird für den View ein anderes Verhalten gewünscht, muss der Controller ausgetauscht werden. Außerdem bleibt durch die Verwendung des Strategy-Musters der View entkoppelt vom Model. Nur der Controller weiß, wie man mit Benutzeraktionen umgeht.

Kapitel 1 Das Projekt Uhr (Observer-Muster, MVC-Muster) Seite 32 Streng genommen verlangt das Strategy-Muster ein Interface, z.b. ControllerInterface, an das alle möglichen Controller angeschlossen werden können. So ähnlich wie bei den Beobachtern müssten alle Controller dieses Interface implementieren. Ich glaube, da in diesem Beispiel nur ein einziger Controller verwendet wird, dass man auf ein ControllerInterface verzichten kann. Genaueres kann man jedoch im eingangs erwähnten Buch Entwurfsmuster von Kopf bis Fuß nachlesen. 1.8 Analoge Anzeige der Uhrzeit In diesem Kapitel wird nun auch eine analoge Darstellung der Uhrzeit entwickelt. Übung 1.22: Betrachte das MVC-Muster in Abbildung 1.27. Überlege, welche der dort dargestellten Datenflüsse im bisherigen Projekt Uhr03b noch nicht berücksichtigt worden ist? Klickt der Benutzer auf den Radiobutton analog, so erhält der Controller vom View die Aufforderung, den View zu ändern. Es muss beispielsweise der andere Radiobutton aktiviert werden (darum musst du dich nicht kümmern, dies macht Swing automatisch) oder die Digitalanzeige muss ersetzt werden durch eine Analoganzeige. Der Controller erhält eine Aktion vom View. In diesem Fall fordert der Controller direkt den View auf, sich zu verändern. Das Model erfährt von dieser Änderung nichts.

Kapitel 1 Das Projekt Uhr (Observer-Muster, MVC-Muster) Seite 33 Abbildung 1.41: Controller weist den View an, sich zu ändern Übung 1.23: Sichere dein bisheriges Projekt als Uhr04. Hole vom Schulserver (oder von meiner Homepage) das Projekt AnalogGUI. Füge mit Hilfe von Add Class from File die Klassen AnalogView und Buehne in dein Projekt Uhr04 ein. Studiere den Quelltext der Klassen AnalogView.und Buehne, auch wenn du nicht alles verstehst. Erzeuge ein Objekt der Klasse AnalogView, es wird eine analoge Uhr mit der 10 15 Uhr dargestellt. Die Klasse AnalogView stellt nur eine andere Sicht der Uhrzeit dar. Da zwischen der Uhr (Model) und den Uhrzeitdarstellungen (View) das Observer-Muster verwendet wurde, muss AnalogView nur noch das Interface Zeitbeobachter

Kapitel 1 Das Projekt Uhr (Observer-Muster, MVC-Muster) Seite 34 implementieren, die vereinbarte Methode empfangeuhrzeit() verwenden und schließlich sich bei Uhr als Zeitbeobachter registrieren lassen. Die Klasse Buehne muss auch noch eine Referenz auf die Uhr erhalten, da die Zeiger ihre aktuellen Stellungen von der Uhr erhalten. Übung 1.24: Implementiere die oben beschriebenen Anweisungen in den Klassen AnalogView und Buehne. Verwende als Vergleich die Klasse DigitalView. Als letzte Aufgabe musst du noch dafür sorgen, dass der Controller auf Benutzereingaben richtig reagiert. Wenn der Benutzer auf den Radiobutton analog drückt, sorgt der Controller dafür, dass sich nur der View ändert. Davon braucht das Modell nichts zu erfahren. In Abbildung 1.27 ist dies durch den Datenfluss 3 und in Abbildung 1.41 durch den roten Pfeil dargestellt. Der Radiobutton analog im SteuerungView muss auf Benutzereingaben reagieren können. Dazu wird in der Methode analogaction() der Controller veranlasst, den AnalogView zu öffnen und den DigitalView zu schließen. private void analogaction() controller.oeffneanalogview(); controller.schliessedigitalview(); Abbildung 1.42: Die Methode analogaction() in der Klasse SteuerungView Der Controller erzeugt nun ein AnalogView-Objekt. Dieses meldet sich selbstständig bei der Uhr als Zeitbeobachter an und kann nun von dieser von jeder Zustandsänderung benachrichtigt werden. Das DigitalView-Objekt wird anschließend unsichtbar gemacht und von der Beobachterliste der Uhr entfernt. Zum Schluss wird es vernichtet. public void oeffneanalogview() analogview = new AnalogView(uhr); public void schliessedigitalview() digitalview.setvisible(false); uhr.entfernebeobachter(digitalview); digitalview.dispose();

Kapitel 1 Das Projekt Uhr (Observer-Muster, MVC-Muster) Seite 35 Abbildung 1.43: Die Methoden oeffneanalogview() und schliessedigitalview() in der Klasse Controller Du erkennst, dass ausschließlich der Controller entscheidet, was mit Benutzereingaben passieren soll. In bestimmten Fällen wird das Modell benachrichtigt, das es seinen Zustand ändern soll, in anderen Fällen wird der View aufgefordert, seine Anzeige zu ändern. Das Model erfährt nichts von dieser Anzeigenänderung, es gibt stur Benachrichtigungen von seinen Zustandsänderungen an alle registrierten Zeitbeobachter weiter. Übung 1.25: Implementiere die Methode analogaction() in der Klasse SteuerungView und die Methoden oeffneanalogview() und schliessedigitalview() in der Klasse Controller. Teste dein Projekt Uhr04, indem du nacheinander ein Taktgeber-Objekt, dann ein Uhr-Objekt und zum Schluss ein Controller-Objekt erzeugst. Beim Drücken auf den Radiobutton analog sollte die Digitalanzeige verschwinden und die Analoganzeige sich öffnen. Übung 1.26: Implementiere nun weitere Methoden, so dass die Anwendung auf das Anklicken des Radiobuttons digital korrekt reagiert. 1.9 Abschlussarbeiten Du hast nun alles, was du brauchst: ein Model, einen View und einen Controller. Und all dies hast du in BlueJ manuell zu einem MVC zusammengesetzt, so dass sie gut miteinander arbeiten. Zum Schluss fehlt noch eine Klasse Simulation, die dies automatisch für dich erledigt. Für eine stand-alone-applikation benötigst du zudem noch die Methode main(). public class Simulation private Taktgeber taktgeber; private Uhr uhr; private Controller controller; public Simulation() Taktgeber taktgeber = new Taktgeber();

Kapitel 1 Das Projekt Uhr (Observer-Muster, MVC-Muster) Seite 36 Uhr uhr = new Uhr(taktgeber); Controller controller = new Controller(taktgeber, uhr); public static void main (String[] args) Simulation q = new Simulation(); Abbildung 1.44: Die Klasse Simulation Übung 1.27: Sichere dein bisheriges Projekt als Uhr05. Implementiere die Klasse Simulation. 1.10 Ausblick Du wirst festgestellt haben, dass dieses Projekt noch einige Mängel aufweist: 1. Die Stellung des Stundenzeigers ändert sich nur jede Stunde. 2. Die Digitalanzeige zeigt beim Umschalten kurzzeitig 00 : 00 an. Hier gibt es noch einige Möglichkeiten, das Projekt zu verbessern. Man könnte auch die Funktionalität der Uhr vergrößern. Folgende Beispiele möchte ich nennen: 1. In der Digitalanzeige könnte man zwischen einer 12-Stunden-Anzeige und einer 24-Stunden-Anzeige wechseln. 2. Das Stellen der Uhr auf eine bestimmte Uhrzeit sollte ermöglicht werden. 3. Die Uhr könnte als Stoppuhr verwendet werden, die man immer wieder mit Hilfe eines Buttons null auf 00 : 00 zurückstellen kann. 4. Die Gestaltung der Anzeigen mit Stunden, Minuten und Sekunden. 5. Zusammenfassung der drei Komponenten des Views (SteuerungView, DigitalView und AnalogView) in ein einziges Fenster. 6. Erstellen weiterer Viewkomponenten (z.b. Darstellung einer Sanduhr). Ich wünsche noch viel Spaß beim weiteren Erforschen der Entwurfsmuster.