Studienarbeit - public.fh

Werbung
FH Braunschweig/Wolfenbüttel
Fachbereich Informatik
Institut für angewandte Informatik
Studienarbeit
Eine Visualisierung vom N. David Mermins EPRExperiment
Eingereicht bei Prof. Dr. rer. nat. habil. R. Rüdiger
Von Heinrich Östreich
[email protected]
Braunschweig, den 23. August 2006
Inhaltsverzeichnis
Inhaltsverzeichnis..................................................................................................... i
Abbildungsverzeichnis............................................................................................. iii
Tabellenverzeichnis................................................................................................ iv
Abkürzungsverzeichnis............................................................................................ v
1. Einleitung............................................................................................................. 1
2. Theoretischer Teil................................................................................................ 2
2.1. Geschichte.................................................................................................... 2
2.2. EPR-Experiment........................................................................................... 3
2.3. EPR-Experiment nach N. David Mermin...................................................... 4
3. Praktischer Teil.................................................................................................... 9
3.1. Visualisierung vom N. David Mermins EPR- Experiment............................. 9
3.2. Anforderungsanalyse.................................................................................... 9
3.3. Applet, Java-Applet.................................................................................... 11
3.4. Modell-View-Controller-Architektur............................................................. 11
4. Implementierung................................................................................................ 16
4.1. Das Interface Config................................................................................... 17
4.2. Das Modell, die Klasse DiceModel............................................................. 19
4.3. Controller, die Klasse SwitchControl.......................................................... 26
4.4. Das View, die Klasse SwitchView............................................................... 28
4.5. Das View, die Klasse LightsView................................................................ 30
4.6. Der Controller, die Klasse AlphaControl..................................................... 33
4.7. Das View, die Klasse AlphaTextView......................................................... 34
4.8. Das View, die Klasse StatisticsView........................................................... 36
4.9. Der Controller, die Klasse ButtonControl.................................................... 37
4.10. Applet, die Klasse PlayDice...................................................................... 38
4.11. Die Klasse InstructionSet......................................................................... 40
4.12. Die Klasse Result..................................................................................... 41
4.13. Die Klasse ResultSeparate....................................................................... 42
4.14. Die Klasse Simulation............................................................................... 43
5. Zusammenfassung............................................................................................ 45
i
6. Ausblick............................................................................................................. 46
Literaturverzeichnis................................................................................................ 47
Eidesstattliche Erklärung....................................................................................... 49
Anhang.................................................................................................................. 50
Quellcode............................................................................................................... 51
AlphaControl.java.............................................................................................. 51
AlphaTextView.java........................................................................................... 51
ButtonControl.java............................................................................................. 52
Config.java......................................................................................................... 52
DelayControl.java.............................................................................................. 56
DelayTextView.java........................................................................................... 57
DiceModel.java.................................................................................................. 57
InstructionSet.java............................................................................................. 65
LightsView.java.................................................................................................. 65
LoopsControl.java.............................................................................................. 67
LoopsTextView.java.......................................................................................... 67
PlayDice.java..................................................................................................... 68
Result.java......................................................................................................... 73
ResultSeparate.java.......................................................................................... 73
Simulation.java.................................................................................................. 74
StatisticsView.java............................................................................................. 74
SwitchControl.java............................................................................................. 75
SwitchView.java................................................................................................. 76
UML-Diagramm..................................................................................................... 77
ii
Abbildungsverzeicnis
Abbildung 1: EPR- Experiment................................................................................ 3
Abbildung 2: EPR-Experiment nach N. David Mermin............................................. 4
Abbildung 3: Einbindung der Visualisierung............................................................ 9
Abbildung 4: MVC-Grundmodell............................................................................ 12
Abbildung 5: MVC-Architektur............................................................................... 13
Abbildung 6: java.util.Observable und java.util.Observer...................................... 14
Abbildung 7: Bereinigtes UML-Klassen-Diagramm................................................ 16
Abbildung 8: Interface Config. Definiert alle Variablen im Programm.................... 17
Abbildung 9: Modell, die Klasse DiceModel........................................................... 19
Abbildung 10: Controller, die Klasse SwitchControl............................................... 26
Abbildung 11: View, die Klasse SwitchView.......................................................... 28
Abbildung 12: View, die Klasse LightsView........................................................... 30
Abbildung 13: Controller, die Klasse AlphaControl................................................ 33
Abbildung 14: View, die Klasse AlphaTextView..................................................... 34
Abbildung 15: View, die Klasse StatisticsView...................................................... 36
Abbildung 16: Controller, die Klasse ButtonControl............................................... 37
Abbildung 17: Applet, die Klasse PlayDice............................................................ 38
Abbildung 18: Ableitungsbaum der Applet-Klasse................................................. 39
Abbildung 19: Die Klasse InstructionSet................................................................ 40
Abbildung 20: Die Klasse Result.java.................................................................... 41
Abbildung 21: Die Klasse ResultSeparate............................................................. 42
Abbildung 22: Die Klasse Simulation..................................................................... 43
Abbildung 23: UML-Diagramm der Anwendung.................................................... 77
iii
Tabellenverzeichnis
Tabelle 1: Bei den Versuchen aufgezeichnete Daten.............................................. 5
Tabelle 2: Gleiche Schalterstellungen führen zu gleichen Farben........................... 5
Tabelle 3: Beliebige Schalterstellungen führen zu zufälligen Farben...................... 5
Tabelle 4: Ergebnisse von einem realen Experiment mit Photonenpolarisation...... 6
Tabelle 5: Zusammenfassung der Ergebnisse........................................................ 7
iv
Abkürzungsverzeichnis
2D
zweidimensional
API
Application Programming Interface
AWT
Abstact Window Toolkit
bzw.
beziehungsweise
d.h.
das heißt
EPR
Einstein Podolski Rosen
ggf.
gegebenenfalls
GUI
Graphical User Interface
HTML
Hypertext Markup Language
JDK
Java Development Kit
JRE
Java Runtime Environment
JVM
Java Virtual Machine
MVC
Model View Controller
SDK
Software Development Kit
u.a.
unter anderem
UML
Unified Modeling Language
z.B.
zum Beispiel
v
1. Einleitung
Die Quantenphysik gehört zu den wichtigsten wissenschaftlichen Revolutionen
des 20. Jahrhunderts und bietet breite Basis für viele moderne Technologien.1
Die zahlreichen experimentelle und theoretische Fortschritte in den vergangenen
Jahrzehnten
führten
zu
einem
Boom
in
der
quantenmechanischen
Grundlagenforschung. Durch verbesserte Techniken ließen sich Experimente
realisieren, die früher nur als „Gedankenexperimente“ galten.2 „Insbesondere die
Frage, ob die Unbestimmtheit quantenphysikalischer Messgrößen lediglich eine
Unkenntnis über die wahren Werte darstellt, oder ob die 'Dinge an sich'
unbestimmt sind, konnte durch experimentelle Befunde zugunsten der letzteren
Aussage erhärtet werden.“3 Eine wichtige Rolle in der Forschung spielt
„Verschränkung“. Dieser Begriff ist zum wichtigen Bestandteil neuer Konzepte in
der Informationstechnologie geworden. Dazu gehören Quantenkommunikation,
-kryptographie und -teleportation, sowie Entwicklung der Quantenrechner.4
Im Folgenden werden zunächst die theoretischen Grundlagen erläutert, auf die
sich diese Arbeit stützt. Im Kapitel 2 wird auf die geschichtliche Entwicklung
eingegangen. Anschließend folgt die Beschreibung des Gedankenexperiments
von Einstein, Podolski und Rosen. Das Kapitel 3 geht ausführlich auf das
Experiment von N. David Mermin ein.
Im praktischen Teil wird zunächst eine Anforderungsanalyse durchgeführt. Die
Umsetzung
des
Programms
wird
in
mehrere
Bereiche
gegliedert.
Die
abschließende Betrachtung des Themas erfolgt im Kapitel 5. Der Ausblick im
Kapitel 6 schließt die Arbeit ab.
1
2
3
4
Vgl. FWF, Stand: 17.08.2006
Vgl. Filk, 2004, S. 13
Götz, 2003, S. 1
Vgl. FWF, Stand: 17.08.2006
1
2. Theoretischer Teil
2.1. Geschichte
Im Jahre 1935 erschien im Physical Review eine Arbeit von Einstein, Podolski und
Rosen mit dem Titel „Can quantum-mechanical description of physical reality be
considered
complete?“.
Darin
beschrieben
die
Wissenschaftler
ein
Gedankenexperiment, das in der Literatur als EPR-Experiment (Einstein, Podolski
und Rosen) genannt wurde und später auch im Labor belegt wurde. Dabei wollten
die Wissenschaftler nachweisen, dass die quantenmechanische Beschreibung der
physikalischen Wirklichkeit unvollständig sein muss.5
Der Ausgangspunkt war das Verhalten der verschränkten Zweiteilchen-Zustände.
Die Quantenteilchen besitzen Welleneigenschaften und sind so miteinander
verbunden, dass sie unabhängig von der Entfernung die gleichen Eigenschaften
aufwiesen. Albert Einstein nannte dieses Phänomen „spukhafte Fernwirkung”. Der
österreichische
Nobelpreisträger
Erwin
Schrödinger
bezeichnete
diese
Eigenschaft als „Verschränkung” und nannte es „Essenz der Quantenphysik“.6
„Verschränkung bedeutet nicht, dass zwei auf diese Art miteinander verbundene
Teilchen in der Beobachtung die gleichen Merkmale aufweisen, einfach weil sie
mit den gleichen Eigenschaften „geboren” sind. Vielmehr bedeutet es, dass eine
Messung, die an einem der beiden Teilchen durchgeführt wird, umgehend den
Zustand des anderen Teilchens beeinflusst.“ 7
Im Jahre 1964 entwickelte John S. Bell eine Bedingung, die alle Theorien, die ein
lokales Realitätskriterium beinhalten, erfüllen müssen. Dies wurde später als
Bellsche
Ungleichung
bezeichnet.
Des
Weiteren
zeigte
Bell,
dass
die
Quantenmechanik diese Bedingung verletzt und beschrieb einen Weg zur
experimentellen Realisation.8 Danach war das Ziel der Physiker die Forderungen
von EPR experimentell umzusetzen und das Ergebnis bezüglich der Bellschen
Ungleichung zu überprüfen. 1982 gelang es Alain Aspect ein Experiment
durchzuführen, welches diese Forderungen erfüllt.9
5
6
7
8
9
Vgl. Wallenborn, 1999, S. 1
Vgl. Zeilinger, Stand: 17.08.2006
Zeilinger, Stand: 17.08.2006
Vgl. Wallenborn, 1999, S. 16
Vgl. Jung, 2003, S. 1
2
Was Einstein als „spukhafte Fernwirkung” bezeichnete, ist heutzutage ein
zentrales Forschungsobjekt für zahlreiche Experimente weltweit und ist ein
wichtiger Bestandteil in dem sich neu entwickelnden Zweig der QuantenInformations-Technologie geworden. Es spielt eine wichtige Rolle bei der
Entwicklung von Quantencomputern und bei der technischen Umsetzung von
Quantenverschlüsselungsverfahren.10
2.2. EPR-Experiment
In diesem Kapitel wird EPR- Experiment detailliert erklärt.
Einstein, Podolski und Rosen betrachten bei ihrem Gedankenexperiment ein
Quantensystem, das in zwei einzelne Teilchen α (Alpha) und β (Beta) zerlegt wird.
Zunächst werden die Teilchen voneinander räumlich getrennt und anschließend
wird eine Messung an einem Teilchen durchgeführt. Die Wissenschaftler haben
erkannt, dass es aufgrund der quantenmechanischen Gesetze möglich ist, eine
Art „telepathische“ Verbindung zwischen zwei Teilchen herzustellen.11 Die
Abbildung 1 veranschaulicht diesen Vorgang.
Abbildung 1: EPR- Experiment
Quelle: eigene Darstellung in Anlehnung an Iliopoulos, 2003, S. 2
Jedes Teilchen kann den Wert „+“ oder „-“ annehmen. Wird am Teilchen α eine
Messung vorgenommen, so wird im gleichen Moment der Wert des Teilchen β
bekannt sein. Ist der Wert des Teilchen α „+“, dann besitzt das Teilchen β den
Wert „-“ und umgekehrt.12 Dieses Phänomen ist auch dann zu beobachten, wenn
die Teilchen durch große Entfernungen voneinander getrennt sind.13
10
11
12
13
Vgl. Zeilinger, Stand: 17.08.2006
Vgl. Tillemans, Stand: 17.08.2006, sowie Wallenborn, 1999, S. 1-2
Vgl. Wallenborn, 1999, S. 1-2, sowie Iliopoulos, 2003, S. 2
Vgl. Tillemans, Stand: 17.08.2006
3
2.3. EPR-Experiment nach N. David Mermin
Bei seinem Experiment verwendete Mermin zwei Detektoren (A und B) und eine
Quelle (C). Die Detektoren stehen weit auseinander. Jeder von denen verfügt über
einen Schalter, der in eine von drei möglichen Positionen gesetzt werden kann.
Beide Detektoren reagieren auf ein Ereignis durch ein Blinken - entweder ein rotes
oder ein grünes Lichtsignal. Die Quelle befindet sich zwischen den Detektoren.
Zwischen den Bestandteilen des Aufbaus (Detektoren A und B und Quelle C)
existiert
weder
mechanische
noch
elektromagnetische
oder
andersartige
Verbindung. Somit ist sichergestellt, dass die Detektoren weder untereinander
noch zur Quelle Signale senden können.
Der Schalter jeden Detektors wird unabhängig und zufällig auf eine seiner drei
Positionen gesetzt. Danach wird der Knopf an der Quelle betätigt. Daraufhin
leuchtet auf jedem Detektor entweder Rot oder Grün auf. Die Einstellungen von
den Schaltern und die aufgeleuchteten Farben werden aufgezeichnet. Das ganze
Verfahren wird mehrmals wiederholt. Die Schaltereinstellungen werden bei jedem
Vorgang zufällig verändert.
Abbildung 2: EPR-Experiment nach N. David Mermin
Quelle: eigene Darstellung
Die Daten bestehen aus einer vierstelligen Zeichenkette, die Zahlen stehen für
Schalterpostionen und Buchstaben für die Lichtsignale. Beispielsweise wurde der
Schalter von A auf 3 und der Schalter von B auf 2 gesetzt. Nach dem Betätigen
des Knopfes an der Quelle leuchtet A Rot und B Grün auf. Das wird als „32RG“
erfasst.14
14 Vgl. Mermin, 1985, S. 4-5
4
Nach jedem Vorgang werden die Ergebnisse aufgezeichnet. Daraus ergibt sich
folgende Wertetabelle (Tabelle 1).
31RR
12GR
23GR
13RR
33RR
12RR
22RR
32RG
13GG
22GG
23GR
33RR
13GG
31RG
31RR
33RR
32RG
32RR
31RG
33GG
11RR
12GR
33GG
21GR
21RR
22RR
31RG
33GG
11GG
23RR
32GR
12GR
12RG
11GG
31RG
21GR
12RG
13GR
22GG
12RG
33RR
31GR
21RR
13GR
23GR
Tabelle 1: Bei den Versuchen aufgezeichnete Daten
Quelle: Mermin, 1985, S. 6
Bei einer Reihe von Experimenten wurde eine Vielzahl an Daten gesammelt.
Diese Daten stellen dennoch nur einen Bruchteil von diesen Werten dar.
31RR
12GR
23GR
13RR
33RR
12RR
22RR
32RG
13GG
22GG
23GR
33RR
13GG
31RG
31RR
33RR
32RG
32RR
31RG
33GG
11RR
12GR
33GG
21GR
21RR
22RR
31RG
33GG
11GG
23RR
32GR
12GR
12RG
11GG
31RG
21GR
12RG
13GR
22GG
12RG
33RR
31GR
21RR
13GR
23GR
Tabelle 2: Gleiche Schalterstellungen führen zu gleichen Farben
Quelle: Mermin, 1985, S. 6
In der Tabelle 2 sind die Datensätze hervorgehoben, bei denen beide Detektoren
die gleichen Schaltereinstellungen haben. Dabei ist auffällig, dass die Lichter
immer die gleichen Farben haben.
31RR
12GR
23GR
13RR
33RR
12RR
22RR
32RG
13GG
22GG
23GR
33RR
13GG
31RG
31RR
33RR
32RG
32RR
31RG
33GG
11RR
12GR
33GG
21GR
21RR
22RR
31RG
33GG
11GG
23RR
32GR
12GR
12RG
11GG
31RG
21GR
12RG
13GR
22GG
12RG
33RR
31GR
21RR
13GR
23GR
Tabelle 3: Beliebige Schalterstellungen führen zu zufälligen Farben
Quelle: Mermin, 1985, S. 6
In der Tabelle 3 sind die Datensätze hervorgehoben, die in jedem Vorgang
blinkten, unabhängig von der Position des Schalters. Dabei ist zu beachten, dass
die Farben vollkommen zufällig sind. Bei den durchgeführten Experimenten ist
Folgendes festzustellen:
● „gleiche Schalterstellung führt mit Sicherheit zu gleicher Farbe: R/R oder
G/G
● beliebige Schalterpositionen führen zu zufälligen Farbkombinationen: R/R,
5
R/G, G/R oder G/G, gleiche und verschiedene Farben gleich häufig
● Gesamtwahrscheinlichkeit für gleiche Farbe: 1/2“15
Dies kann in einem realen Experiment mit Photonenpolarisation bestätigt werden.
Alice
1
Bob
2
3
1
2
3
1
2
3
1
2
3
1
1/4
1/4
1/4
1
1/4
1/4
1/4
1
Schalterposition
Wahrscheinl. für
gleiche Farbe
Tabelle 4: Ergebnisse von einem realen Experiment mit Photonenpolarisation
Quelle: Rüdiger, 2004, S. 17
Die Wahrscheinlichkeit für gleiche Farbkombinationen wird folgendermaßen
errechnet:
Pr [gleiche Farbe] =
1
3
*
1
3
(3*1+3*2*
1
4
)=
1
2
Bei zwei Detektoren mit je drei möglichen Schalterpositionen (1/3 * 1/3 oder 2 *
1/3) ist bei den Kombinationen mit den gleichen Schalterstellungen (11, 22 und
33) an den Detektoren die Wahrscheinlichkeit für gleiche Farbkombinationen
jeweils gleich eins (3 * 1) und bei anderen Schalterpositionen (12, 13, 21, 23, 31
und 32) ist dieselbe Wahrscheinlichkeit jeweils gleich einviertel (3 * 2 *1/4). Was
nach dem Ausrechnen ½ ergibt.
Dies kann dann zustande kommen, wenn:
● Alice und Bob untereinander kommunizieren und/oder
● das Ergebnis hängt von dem Zufallsereignis ab, das vorher ausgewürfelt
wird
Die erste Erklärung widerspricht der speziellen Relativitätstheorie. Die zweite
Erklärung ist ebenfalls nicht zutreffend, da diese bereits bei einem Experiment mit
3 Schalterpositionen, wie oben beschrieben, nicht funktioniert. Dies wird im
folgenden statistischen Experiment beschrieben:
15 Rüdiger, 2004, S. 16
6
Bei zwei unterschiedlichen Farben (rot und grün) und drei Schalterpositionen (1, 2
und 3) sind acht Farbkombinationen möglich, die im Folgenden als Instruktionen
bezeichnet werden (RRR, RRG, RGR, RGG, GRR, GRG, GGR und GGG). Dabei
stehen beispielsweise bei der Instruktion GRR für grün bei Schalterposition 1, rot
bei 2 und rot bei 3.16
Wenn alle Möglichkeiten für einen Versuchsaufbau mit zwei Detektoren
aufgezeichnet werden, ergibt sich folgende Tabelle 5:
Schalterposition
gleiche Farbe
Instruktion
1
2
3
Wahrsch.
1
R
R
R
11
22
33
12
13
21
23
31
32
p1
2
R
R
G
11
22
33
12
13
21
23
31
32
p2
3
R
G
R
11
22
33
12
13
21
23
31
32
p3
4
R
G
G
11
22
33
12
13
21
23
31
32
p4
5
G
R
R
11
22
33
12
13
21
23
31
32
p5
6
G
R
G
11
22
33
12
13
21
23
31
32
p6
7
G
G
R
11
22
33
12
13
21
23
31
32
p7
8
G
G
G
11
22
33
12
13
21
23
31
32
p8
Gelb = ungleiche Farbe
Tabelle 5: Zusammenfassung der Ergebnisse
Quelle: eigene Darstellung in Anlehnung an Rüdiger, 2004, S. 20
Aus der obigen Tabelle kann entnommen werden, dass bei den Instruktionen 1
und 8 die Wahrscheinlichkeit für gleiche Farbe gleich 1 (9/9) ist. Bei den
Instruktionen 2 bis 7 ist die Wahrscheinlichkeit für gleiche Farbe hingegen 5/9. Die
Gesamtwahrscheinlichkeit für gleiche Farbe wird nach folgender Formel
berechnet:
Die
Summe
von
α
und
β
ist
16 Vgl. Rüdiger, 2004, S. 16 ff.
7
gleich
eins
und
entspricht
der
Gesamtwahrscheinlichkeit, dass die gleiche Farbkombination ausfällt.17
7
α := ∑ pi , β: =p1 + p8 und
α+β=1
i -1
Daraus
ergibt
sich
die
Wahrscheinlichkeit
für
gleiche
Farbe
mit
dem
Instruktionensatz:
p
mit Instruktion:=
Pr [gleiche Farbe] = 1 -
4
9
α,
0 ≤ α ≤1
Die Wahrscheinlichkeit für gleiche Farbe mit dem Instruktionensatz ist also
beschränkt gemäß:
1/2 < 5/9 ≤ p
mit Instruktion
≤1
Aus den vorhergegangenen Experimenten und aus der Wahrscheinlichkeitstheorie
ist jedoch bekannt, dass:
pquantenmechanisch = 1/2
Daraus ergibt sich:
● die so genannten lokalrealistischen Theorien sind widerlegt
● eine Erklärung mittels klassischer Physik ist nicht möglich18
John Preskill sagte in diesem Zusammenhang: „.... To some people, the peculiar
correlations unmasked by Bell's theorem call out for a deeper explanation than
quantum mechanics seems to provide. They see the EPR phenomenon as a
harbinger of new physics awaiting discovery. But they may be wrong. We have
been waiting over 60 years since EPR, and so far no new physics.“19
17 Vgl. Rüdiger, 2004, S. 20-21
18 Vgl. Rüdiger, 2004, S. 19
19 Rüdiger, 2004, S. 22
8
3. Praktischer Teil
3.1. Visualisierung vom N. David Mermins EPR- Experiment
Ziel dieser Arbeit ist es, eine Visualisierung vom Mermins EPR- Experiment zu
entwickeln. Schon lange vor Erfindung des Computers diente die Visualisierung
als ein wichtiges Hilfsmittel zum Verständnis technisch-wissenschaftlicher
Zusammenhänge. Die Visualisierung kann nach folgendem Muster ablaufen:
Abbildung 3: Einbindung der Visualisierung
Quelle: Lehle, 1997, S. 13
Der Mensch beobachtet ein Objekt und führt Experimente mit diesem durch, die
ihm
Messdaten
liefern.
Die
Ergebnisse
werden
mit
geeigneten
Computerprogrammen in Bilder umgewandelt. Dieser Vorgang wird durch
mathematische Erkenntnisse erweitert, welche erlauben Schlüsse zu ziehen und
Vorhersagen zu machen.20
3.2. Anforderungsanalyse
Unter
Anforderungsanalyse
wird
ein
Teil
des
Software-
und
Systementwicklungsprozesses bezeichnet, der dazu dient, die Anforderungen des
Auftraggebers an das zu entwickelnde System oder ein Anwendungsprogramm zu
ermitteln.21 Bei einer objektorientierten Entwicklung werden die Objekte des
20 Vgl. Lehle, 1997, S. 13
21 Vgl. Wikipedia, Stand: 17.08.2006
9
Anwendungsbereichs analysiert und anschließend strukturiert, so dass das
erstellte Modell ein Gerüst für die Implementierung darstellt. Das zu entwickelnde
System soll korrekt, vollständig, eindeutig, verständlich und nachvollziehbar erklärt
werden.22
Um das Experiment von N. David Mermin visuell umsetzen zu können, müssen,
bezugnehmend auf seinen Versuchsaufbau, folgende Bestandteile vorhanden
sein:
● A und B: zwei Detektoren, die jeweils mit einem Schalter und zwei Lichtern
(rot und grün) ausgerüstet sind. Jeder Schalter kann auf die Positionen 1, 2
oder 3 eingestellt werden.
● C: eine Quelle, die das Signal an die Detektoren aussendet.
Zusätzlich sind folgende Komponenten erforderlich:
● Eine Möglichkeit, um die Werte für Alpha und Beta einzustellen.
● Graphische Darstellung der Ergebnisse, wie oft (prozentual) wurde die
gleiche Farbe an den Detektoren A und B angezeigt.
● Eine
Möglichkeit,
die
Anzahl
der
durchzuführenden
Experimente
einzustellen.
● Eine Komponente, mit der sich die Ausführungsgeschwindigkeit einstellen
lässt.
Damit der Anwender das Programm von einem beliebeigen Web-Browser aus
ausführen kann, erfolgt die Umsetzung als Applet in der Programmiersprache
Java. Darüber hinaus soll eine spätere Änderung oder Erweiterung des Systems
einfach durchführbar sein. Weiterhin soll sichergestellt werden, dass die einzelnen
Module des Programms wiederverwendbar sind. Um diese Forderungen zu
erfüllen und um die Trennung der Verarbeitungslogik von der Darstellung zu
erreichen, ist es erforderlich bei der Implementierung das Modell-View-ControllerPrinzip (MVC-Prinzip) anzuwenden.
22 Vgl. Meißner, 2002, S. 31
10
3.3. Applet, Java-Applet
Java-Applet ist ein in der Programmiersprache Java geschriebenes und im WebBrowser oder Applet-Viewer lauffähiges Programm.23 Applets werden aus einer
HTML-Seite aufgerufen und in der Java Virtual Machine (JVM) auf dem Rechner
ausgeführt. Die JVM kann entweder ein Teil des Web-Browsers sein oder in Form
einer Java-Laufzeitumgebung auf dem Rechner nachträglich installiert werden. Da
die Applets auf dem Rechner des Anwenders ausgeführt werden, stellen diese ein
Sicherheitsrisiko dar. Da sie jedoch nur innerhalb einer JVM ausgeführt werden
können, ist dieses Risiko kontrollierbar.24 Im Unterschied zu normalen JavaApplikationen
dürfen
Applets
nicht auf das
Dateisystem
zugreifen
und
beispielsweise Dateien löschen.25 Zu Problemen kann es nur dann kommen, wenn
die JVM fehlerhaft ist.
Vorteilhaft an der Applet-Technologie ist der volle Funktionsumfang aus der J2SEAPI unter Berücksichtigung der Sicherheitsregeln. Außerdem eignen sich Applets
gut für Anwendungen in firmeninternen Netzwerken, bei denen alle Anwender die
gleiche Java-Version haben. Als Nachteil wird die Größe der Java Runtime
Environment (JRE) angesehen, die bei Sicherheitsproblemen komplett neu
heruntergeladen und installiert werden muss (etwa alle 1–2 Monate).26
3.4. Modell-View-Controller-Architektur
Wie auf der Abbildung 4 zu sehen ist, besteht die klassische MVC-Architektur aus
drei Bestandteilen: dem Modell, dem View und dem Controller. Das MVC-Prinzip
hat als Ziel die Trennung der Verarbeitung eines Problemgebietes von dessen
Präsentation zu ermöglichen. So eine Trennung erlaubt flexibles Programmdesign,
das die spätere Änderung oder Erweiterung vereinfacht. Weiterhin reduziert das
MVC-Konzept
die
Komplexität
des
Programm
Übersichtlichkeit.
23
24
25
26
Vgl. Krüger, 2003, S. 273
Vgl. Wikipedia, Stand: 17.08.2006
Vgl. Ullenboom, 2005, Stand: 17.08.2006
Vgl. Wikipedia, Stand: 17.08.2006
11
und
verbessert
dessen
Abbildung 4: MVC-Grundmodell
Quelle: eigene Darstellung
● „Das Modell enthält die Daten des Dialogelements und speichert seinen
Zustand.
● Der View ist für die grafische Darstellung der Komponente verantwortlich.
● Der Controller wirkt als Verbindungsglied zwischen beiden. Er empfängt
Tastatur- und Mausereignisse und stößt die erforderlichen Maßnahmen zur
Änderung von Model und View an.“27
Das Modell beinhaltet die gesamte Verarbeitungslogik. Dabei ist zu beachten,
dass ein Model mehrere Views gleichzeitig haben kann. „Damit Veränderungen
des
Modells
in
allen
Benachrichtigungsmechanismus
zugeordneten Views über
Views
sichtbar
implementiert,
mit
werden,
dem
das
wird
ein
Modell
die
Änderungen informiert. Diese Vorgehensweise
entspricht dem Observer-Pattern.“28
Vorteilhaft an einer MVC-basierten Architektur ist die Möglichkeit durch die
Trennung der einzelnen Teile das Aussehen einer Komponente zu verändern.
Dabei ist es nicht notwendig deren Verhalten zu modifizieren. Als Nachteil wird die
strikte Trennung von View und Controller angesehen, da dadurch die
Kommunikation zwischen diesen Bestandteilen komplex und unüberschaubar
werden kann.
Die MVC-Architektur entkoppelt das mathematische Modell von der eigentlichen
Programmsteuerung. Dabei erfolgen die Auswertung der Eingaben und Ausgaben
getrennt. Die Abgrenzung dieser Aufgaben wird durch drei Klassen, Modell, View
und Controller ermöglicht.
27 Krüger, 2003, S. 751
28 Krüger, 2003, S. 751
12
Abbildung 5: MVC-Architektur
Quelle: Meiler, o.J., S. 3
Das Modell enthält die Daten und Kernfunktionalität der Anwendung. Es ist
unabhängig von den anderen Komponenten und hat folgende Aufgaben: es kennt
alle Views und Controller, die zum Einsatz kommen, und informiert diese über
Änderung in den Anwenderdaten. View ermöglicht die Darstellung der Daten aus
dem Modell und reagiert auf Datenveränderungen im Modell. Controller nimmt die
Eingaben des Benutzers entgegen und reicht diese an das Model weiter. Ein
Controller kann auf ein spezielles View zugeschnitten sein.29
Von den Veränderungen im Modell ist das Verhalten des View und eventuell des
Controllers abhängig. Daher müssen View und Controller das Modell überwachen.
Um dies zu ermöglichen, stellt Java folgende Klassen bereit:
● Observable, die überwachten Klassen (Modell) werden von dieser Klasse
abgeleitet.
● Observer, die überwachenden Klassen (View, Controller) implementieren
dieses Interface.
Die Klasse Observable (java.util.Observable) bietet folgende Funktionalität:
● Verwaltung beliebig vieler Observer
● Registrierung der Observer
29 Vgl. Meiler, o.J., S. 3
13
● Änderungen in den Anwenderdaten werden registriert
● Registrierten Observern werden die Änderungen mitgeteilt
● Streichung der Observer aus der Observerliste
Klassen, welche eine andere Klasse überwachen, implementieren das Interface
Observer (java.util.Observer), dabei muss nur die Methode update() realisiert
werden.30 Die Methode update(Observable, Object) wird bei bei Änderungen des
Observable-Objektes aufgerufen. Das zweite Argument der update()-Methode ist
die hereinkommende Nachricht, welche über die Methode notifyObservers()
versendet wurde.31 Der Mechanismus zur Überwachung wird in der Abbildung 6
dargestellt.
Abbildung 6: java.util.Observable und java.util.Observer
Quelle: Meiler, o.J., S. 3
Zunächst wird die Klasse Modell als Ableitung der Klasse Observable
implementiert.
Dabei
werden
die
Methoden
zum
Lesen
getData()
der
darzustellenden Daten coreData und service() öffentlich gemacht. Durch die
Observable-Methoden
setChanged()
und
notifyObservers()
werden
die
Änderungen veröffentlicht.
In der Klasse View wird die draw()-Methode implementiert und übernimmt die
Einrichtung des Überwachungsmechanismus. Diese ist für die Datenausgabe
zuständig und ist von der verwendeten Plattform abhängig. Die Verbindung zu den
Modell- und Controller-Klassen wird mittels der initialize()-Methode hergestellt.
30 Vgl. Meiler, o.J., S. 4
31 Vgl. Ullenboom, 2005, Stand: 17.08.2006
14
Diese Methode richtet das View als Observer des Modells mit Hilfe von
addObserver() ein. Ein für diese View-Klasse spezifischer Controller wird mit der
Methode makeController() geschaffen. Mittels der getData()-Methoden greift View
auf die Daten der Klasse Modell zu. Über die update()-Methode wird die
Benachrichtigung über die Änderungen implementiert.
Die View-Klasse steuert auch die Abmeldung des Überwachungsmechanismus.
Dabei meldet die Methode release() das View beim Modell ab, löst die
Verbindungen zu ihm und gibt die nicht mehr benötigten Ressourcen frei.
Die Klasse Controller reagiert mittels der handleEvent()-Methoden auf die
Eingaben des Benutzers. Die Beziehung der Controller-Klasse zu den Modell- und
View-Klassen wird über eine initialize()-Methode aufgebaut. Bei Bedarf richtet die
Methode initialize() den Controller über addObserver() als Observer des Modells
ein. Mittels der update()-Methode kann der Controller auf Veränderung der Daten
reagieren. Die getData()-Methoden erlauben dem Controller die Informationen aus
dem Modell abzurufen. Über die service()-Methoden übergibt die Klasse Controller
die Eingaben des Benutzers an das Modell.32
32 Vgl. Meiler, o.J., S. 4-5
15
4. Implementierung
Im Folgenden wird die Implementierung der Visualisierung des EPR-Experimentes
von N. David Mermin detailliert dargestellt. Bei der Realisierung wurde auf die
Erfüllung aller an das Programm gestellter Anforderungen ein großer Wert gelegt.
Für den Aufbau des Simulators wurde das Modell-View-Controller-Prinzip
angewendet. Auf der Abbildung 7 ist das um Attributen und Operationen
bereinigtes UML-Klassen-Diagramm des Applets zu sehen.
Im weiteren Verlauf der Arbeit wird genauer auf einzelne Komponenten des
Abbildung 7: Bereinigtes UML-Klassen-Diagramm
Quelle: eigene Darstellung
16
4.1. Das Interface Config
Im Interface Config sind alle Variablen definiert, die von den anderen Klassen
verwendet werden. Die Abbildung 8 zeigt das Diagramm dieses Interface in UMLNotation.
Abbildung 8: Interface Config. Definiert alle Variablen im Programm.
Quelle: eigene Darstellung
Diese Variablen sind den anderen Klassen nur über das Model, die Klasse
DiceModel zugänglich. Dieser Mechanismus wurde zwecks einfacherer Wartung
des Programms eingerichtet – alle Variablen des Programms sind in diesem
Interface zentral versammelt und müssen somit nur da geändert werden.
Anschließend ist nur eine Neukompilierung des Programms notwendig. Einige
Variablen werden in diesem Interface errechnet, wie beispielsweise die Variable
zur Berechnung des Umfangs des Kreises im Bogenmaß:
...
045
046
// Umfang des Kreises im Bogenmaß
static final double sphere = 2 * Math.PI;
...
17
Dabei wird auch der Kreis für den Schalter definiert:
...
091
092
093
// Circle
static final Ellipse2D circle = new Ellipse2D.Double(zX - rR * rV,
zY - rR * rV, 2 * rR * rV, 2 * rR * rV);
...
Die bei den Berechnungen verwendeten Variablen sind ebenfalls im Interface
definiert, z.B. die Mitte des Panels, welche über die x- und die y-Koordinaten
festgelegt wird, und vordefinierter Radius des Elementes:
...
015
016
017
018
019
020
// x- Koordinate der Panelmitte
static final int zX = 100;
// y- Koordinate der Panelmitte
static final int zY = 100;
// Radius eines Kreises
static final int rR = 75;
...
Des weiteren wird sichergestellt, dass der Mausklick auch in einem definierten
Bereich (in diesem Fall 20%) außerhalb des sichtbaren Kreises noch gültig ist:
...
041
042
// Noch gueltiger Radius
static final double rV = 1.20;
...
Außerdem sind in Config die Strings definiert, wie beispielsweise die Beschriftung
der Buttons oder Tooltips:
...
144
145
// Beschriftung des Buttons START
static final String stringStart = "START";
...
164
165
166
// ToolTip fuer den Button START
static final String sToolTipStart =
new String("Press the button to run this program");
...
18
4.2. Das Modell, die Klasse DiceModel
Die Abbildung 9 zeigt das Diagramm der Klasse DiceModel in der UML-Notation.
Abbildung 9: Modell, die Klasse DiceModel
Quelle: eigene Darstellung
19
Die
Klasse
DiceModel
wird
von
der
Java-eigenen
Klasse
Observable
(java.util.Observable) abgeleitet und implementiert das Interface Runnable
(java.lang.Runnable). Sie enthält die Kernfunktionalität der Anwendung. Über
diese Klasse werden alle Variablen aus dem Interface Config den anderen
Klassen zur Verfügung gestellt:
...
117
118
protected final String stringStart = Config.stringStart;
// Beschriftung des Buttons STOP
...
136
137
// ToolTip fuer den Button START
protected final String sToolTipStart = Config.sToolTipStart;
...
In der Methode notificationOfChange() wurden die von der Klasse Observable
bereitgestellten Methoden setChanged() und notifyObservers() zusammengefasst.
Somit wird bei Aktualisierungen in anderen Methoden nur notificationOfChange()
aufgerufen, welche dadurch die Änderungen veröffentlicht.
...
295
296
297
298
final private void notificationOfChange() {
setChanged();
notifyObservers();
}
...
In der Methode setSwitch() wird der Schalter (hier Switch) umgestellt. Dazu wird
bei einem Klick innerhalb des Kreises und in einem gültigen Bereich außerhalb
dessen (zusätzlich 20% zum Radius des Kreises) von der Klasse ButtonControl
die Koordinate des Klicks an das Modell durchgereicht. Dabei wird mittels der
booleschen Variablen LEFT (entspricht true, Zeile 006 im Interface Config) und
RIGHT (entspricht false, Zeile 008 im Interface Config) zwischen den Schaltern A
und B unterschieden. Hierbei ist die Variable LEFT dem Schalter A und die
Variable RIGHT dem Schalter B zugeordnet. In der Methode setSwitch() werden
diese Informationen dazu verwendet, um den Zeiger des jeweiligen Schalters in
die gewünschte Position zu bringen. Bei der Berechnung wird die Position des
Klicks in Relation zum Zentrum des Kreises bestimmt. Der Kreis ist in drei gleich
große Bereiche eingeteilt worden. In Abhängigkeit davon in welchem Bereich des
Kreises der Mausklick erfolgte, wird ein Wert ermittelt. Dieser Wert ist eine Zahl (in
20
Java int – Integer), die nur 0, 1 oder 2 sein kann. Diese Zahlen werden in der
Klasse SwitchView den Schalterpositionen 1, 2 oder 3 entsprechend zugeordnet.
...
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
final protected void setSwitch (int sourceX,
int sourceY, boolean lr) {
adjacent = sourceX - zX;
opposite = zY - sourceY;
hypotenuse = Math.sqrt((adjacent * adjacent) +
(opposite * opposite));
angle = Math.acos(adjacent / hypotenuse);
if (opposite > 0) {
angleXY = sphere - angle + shiftScan;
} else {
angleXY = angle + shiftScan;
}
if (lr == LEFT) {
signalSwitchLeft = (int) ((angleXY /
(sphere / parts)) % parts);
} else if(lr == RIGHT) {
signalSwitchRight = (int) ((angleXY /
(sphere / parts)) % parts);
}
notificationOfChange();
}
...
Die Methode getSwitch() gibt die Werte zurück, die in der Methode setSwitch()
ermittelt wurden. Dabei wird auch unterschieden, ob es sich um Schalter A (hier
LEFT) oder B (hier RIGHT) handelt.
...
262
263
264
265
266
267
268
269
270
271
272
final protected int getSwitch(boolean lr) {
if (lr == LEFT) {
return signalSwitchLeft;
} else if(lr == RIGHT) {
return signalSwitchRight;
} else {
// exception
// because of boolean is unreachable
return 0;
}
}
...
Die Methode setLights() ist zuständig für die korrekte Ausgabe der Lichtsignale in
den Detektoren A und B. In der Zeile 327 wird ein neues InstructionSet-Objekt
erzeugt. Die Information über auszugebende Farbe wird mittels der Klasse
ResultSeparate aus der Klasse InstructionSet gewonnen. Dies wird in der
21
Methode setLights() dazu verwendet, um den Wert für eine Farbe zu setzten: rot =
0, grün = 1 und weiß = default = 2.
...
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
final protected void setLights(int instrNumber,
int signalSwitch, boolean lr) {
int lightsValue;
if(lr == LEFT) {
this.signalSwitchLeft = signalSwitch;
} else if(lr == RIGHT) {
this.signalSwitchRight = signalSwitch;
} else {
// not reachable
// because of boolean is unreachable
}
InstructionSet instrSet = new InstructionSet();
ResultSeparate result = instrSet.apply
(instrNumber, signalSwitch); // deterministic
if (result.toString() == "R") { // Light, RED
lightsValue = 0;
} else if (result.toString() == "G" ) { // Light, GREEN
lightsValue = 1;
} else if (result.toString() == "D" ) { // Light, DEFAULT
// only with RESET reachable
lightsValue = 2;
} else { // Light, DEFAULT
lightsValue = 2;
}
if (lr == LEFT) {
this.signalLightsLeft = lightsValue;
} else if (lr == RIGHT) {
this.signalLightsRight = lightsValue;
} else {
// not reachable
}
notificationOfChange();
}
...
Die Methode getLights() liefert die in der Methode setLights() ermittelten Werte
zurück. Dabei wird an dieser Stelle ebenfalls unterschieden, ob es sich um das
Lichtsignal für Detektor A oder B handelt.
...
349
350
351
352
353
354
355
final protected int getLights (boolean lr) {
if(lr == LEFT) {
return signalLightsLeft;
} else if(lr == RIGHT) {
return signalLightsRight;
} else {
// exeption
22
356
357
358
359
// because of boolean is unreachable
return 0;
}
}
...
Die
Methode
setStatistics()
berechnet
den
durchschnittlichen
Wert
(statisticsAverage) mit Hilfe vom Zähler für gleiche Farbe in den Detektoren A und
B (countLights) und mittels Zählers für die Gesamtzahl der Experimente
(countClicks). Dieser Wert wird verwendet von der Klasse StatisticsView um den
Fortschrittsbalken zu aktualisieren.
...
299
300
301
302
303
304
305
306
307
308
309
310
311
312
final protected void setStatistics (int countClicks,
int countLights) {
if (countClicks != 0) {
statisticsAverage = statisticsMax *
countLights / countClicks;
} else if (countClicks == 0) {
// Ueber RESET erreichbar
// weil setStatistics(0, 0); aufgerufen wird
// notwendig um StatisticsView (JProgressBar)
// auf 0 zurueckzusetzen
statisticsAverage = statisticsMin;
}
notificationOfChange();
}
...
Da bestimmte Objekte der Klasse DiceModel als Thread (java.lang.Thread)
ablaufen sollen, implementiert diese das Interface Runnable. Nach dem Betätigen
des „START“-Buttons wird in der Klasse ButtonControl mit dem Aufruf der
Methode start() der Thread gestartet. Die Methode start() ist ein Bestandteil von
Thread, welche für die Steuerung (starten, beenden) von Threads zuständig ist.
Die Methode run() wird innerhalb eines Thread ausgeführt. Darin wird der
auszuführende Programmcode eingebettet. In dem vorliegenden Fall ist es die forSchleife. Die Klasse LoopsControl gibt vor, wie oft diese for-Schleife durchlaufen
wird. Dabei wird unterschieden, ob die Anzahl von Schleifen gleich oder größer
eins ist. Der Unterschied besteht darin, dass bei genau einer Schleife der
Anwender selbst die Positionen der Schalter A und B bestimmt, d.h. jedes
Experiment wird einzeln durchgeführt. Bei mehr als einer Schleife werden die
Positionen der Schalter A und B „automatisch“ mittels eines Zufallsgenerators
umgestellt. Damit kann der Anwender mehrere Experimente auf einmal
23
durchführen. Weiterhin sind der Gesamtzähler (countLoops) und der Zähler für
gleiche Farben in den Detektoren A und B (countLights) in dieser Methode
untergebracht. Von hier aus wird mit diesen Zählern die Methode setStatistics()
aufgerufen. Die for-Schleife bzw. die Methode run() kann vom Anwender durch
Betätigen des Buttons „STOP“ angehalten werden. Nach der Abarbeitung des
Threads oder dessen Anhalten wird in der Zeile 399 die Methode setBStop() der
Klasse PlayDice aktiviert. Diese Methode sperrt bzw. gibt bestimmte Buttons frei.
Weiterhin kann der Anwender die Ausführungsgeschwindigkeit des Threads
bestimmen (Zeile 373). Dabei wird die Geschwindigkeit stufenlos mittels
Einstellung der Verzögerung (delay) reguliert. Die Verzögerung kann damit in
einem Bereich zwischen null Sekunden (entspricht keiner Verzögerung, somit
normale Ausführgeschwindigkeit) und den momentan im Interface Config
definierten
zwei
Sekunden
eingestellt
werden.
Die
Kontrolle
der
Ausführungsgeschwindigkeit wurde mit einer try-catch-Anweisung ergänzt, um
mögliche Fehler abzufangen.
...
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
final public void run() {
InstructionSet instrSet = new InstructionSet();
Simulation sim = new Simulation(instrSet);
Result result;
alpha = getValueAlpha();
loops = getValueLoops();
stop = false;
int switchL = 0;
int switchR = 0;
countClicks = getCountClicks();
countLights = getCountLights();
for (int k = 0; (k < loops) && (!stop); k++) {
try {
Thread.sleep(delayMax - getValueDelay());
} catch (InterruptedException ie) {
ie.printStackTrace();
}
int instrNo = sim.chooseInstruction(alpha);
if (loops == loopsLimit) { // Loops == 1
switchL = getSwitch(LEFT);
switchR = getSwitch(RIGHT);
} else if (loops > loopsLimit) { // Loops > 1
switchL = sim.chooseSwitch();
switchR = sim.chooseSwitch();
} else { // Loops == null or negative
// not reachable
System.err.println("DiceModel.run(): ERROR!");
24
387
388
389
390
391
392
393
394
395
396
397
398
399
400
}
result = instrSet.apply(instrNo, switchL,
switchR); // deterministic
setLights(instrNo, switchL, LEFT);
setLights(instrNo, switchR, RIGHT);
countClicks++;
if (result.colorL == result.colorR) {
countLights++;
}
setStatistics(countClicks, countLights);
}
stop = false;
pd.setBStop();
}
...
Die Methode resetAll() wird durch Betätigen des Buttons „RESET“ über die Klasse
ButtonControl aktiviert. Diese Methode ermöglicht dem Anwender das Programm
auf die Starteinstellungen bei Bedarf zurückzustellen.
...
221
222
223
224
225
226
227
228
229
230
231
final protected void resetAll() {
setValueAlpha(startAlpha);
setValueLoops(startLoops);
setValueDelay(startDelay);
setStatistics(resetStatCC, resetStatCL);
setCountClicks(resetStatCC);
setCountLights(resetStatCL);
setLights(defaultLights, startSwitch, LEFT);
setLights(defaultLights, startSwitch, RIGHT);
notificationOfChange();
}
...
Weiterhin besteht die Klasse DiceModel aus einigen set- und get-Methoden, die
unterschiedliche Variablen für die Berechnungen und Ausgaben zuordnen bzw.
bereitstellen. Als Beispiel sind die Methoden setValueAlpha() und getValueAlpha()
zu nennen:
...
273
274
275
276
277
278
279
280
final protected void setValueAlpha (int valueAlpha) {
this.valueAlpha = valueAlpha;
valAlpha = (double) valueAlpha / (double) alphaMax;
notificationOfChange();
}
final protected double getValueAlpha() {
return valAlpha;
}
...
25
In der Methode setValueAlpha() wird die Varibale valAlpha gesetzt. Der Wert von
Alpha darf zwischen null und eins liegen. Mit JSlider lässt sich dieser
Wertebereich jedoch nicht präzise einstellen. Daher wurde ein wesentlich größerer
Wertebereich (0 bis 1000) definiert, der innerhalb des Programms anhand einer
Transformation umgerechnet wird.
Die Methode getValueAlpha() hat die Variable valAlpha als Rückgabewert.
valAlpha wird später von der Klasse AlphaTextView zur graphischen Darstellung
des Wertes als Text verwendet. Weiterhin wird diese Variable beim Aufruf der
Methode chooseInstruction() der Klasse Simulation als Parameter übergeben, um
damit die Berechnungen zur Auswahl der Instruktion durchzuführen.
Über set- und get-Methoden wird sichergestellt, dass andere Klassen oder
Methoden auf Variablen zugreifen können. Andere set- und get-Methoden sind
ähnlich aufgebaut, aber derartige Berechnungen werden von diesen Methoden
nicht durchgeführt. Daher wird auf diese Methoden im Einzelnen nicht weiter
eingegangen.
4.3. Controller, die Klasse SwitchControl
Auf der Abbildung 10 ist das vollständige Diagramm der Klasse SwitchControl
nach der UML-Notation zu sehen. Mittels dieser Klasse werden die Schalter A und
B zwischen den Positionen 1, 2 oder 3 umgestellt.
Abbildung 10: Controller, die Klasse SwitchControl
Quelle: eigene Darstellung
Da die Positionen der Schalter im Programm mittels eines Klicken mit der Maus
umgestellt
werden,
wird
diese
Klasse
von
der
Klasse
MouseAdapter
(java.awt.event.MouseAdapter) abgeleitet (Zeile 05). MouseAdapter stellt dabei
eine
leere
Implementierung
der
Klasse
MouseListener
(java.awt.event.MouseListener) dar. „MouseListener definiert eine Schnittstelle für
Klassen, die vom Auftreten eines MouseEvent benachrichtigt werden wollen.“33
33 Middendorf u.a., Stand: 17.08.2006
26
Diese Implementierung ermöglicht in der Klasse SwitchControl nur die Methoden
zu überschreiben, die tatsächlich von dem Programm benötigt werden. Da das
Umstellen des Schalters auf einen Mausklick erfolgen soll, wird in diesem Fall nur
die Methode mouseClicked() überschrieben.
In der Methode mouseClicked() wird geprüft, ob der Mausklick innerhalb des
definierten Bereiches (der Kreis plus 20% vom Radius, ist im Interface Config
definiert, darauf kann nur über die Klasse DiceModel zugegriffen werden) oder
außerhalb dessen erfolgte. Im Falle positiver Überprüfung wird die Koordinate des
Mausklicks an das Modell (die Klasse DiceModel) weitergereicht, genauer an die
Methode setSwitch(). Diese Weitergabe erfolgt in Verbindung mit der Information,
um welchen Schalter es sich handelt – A oder B.
Weiterhin ist eine optionale Möglichkeit vorgesehen, um mittels Bewegung der
Maus innerhalb eines vorher definierten Bereiches den Schalter umzustellen. Um
diese Möglichkeit zu nutzen, müssen in dieser Klasse alle Zeilen, die für das
Reagieren auf Mausklick zuständig sind (Zeilen 03, 06, 12, 13 und 19)
auskommentiert und in den Zeilen 02, 05, 10, 11 und 18 die Kommentarzeichen
entfernt. Dann müssen in der Klasse PlayDice die Zeilen 253 und 257
auskommentiert werden und in den Zeilen 252 und 256 die Kommentarzeichen
entfernt werden. Anschließend muss das Programm neu kompiliert werden, damit
diese Funktionalität zur Verfügung steht. Dadurch wird die Klasse SwitchControl
nun von der Klasse MouseMotionAdapter (java.awt.event.MouseMotionListener)
abgeleitet.
Analog zu den Klassen MouseAdapter und MouseListener stellt die Klasse
MouseMotionAdapter
(java.awt.event.MouseMotionAdapter)
Implementierung
der
zu
Klasse
MouseMotionListener
eine
leere
(java.awt.event.
MouseMotionListener) und ermöglicht das Überschreiben von nur solcher
Methoden, die auch tatsächlich verwendet werden. In diesem Fall handelt es sich
um die Methode mouseMoved().
01
02
03
04
05
06
import java.awt.event.MouseEvent;
// import java.awt.event.MouseAdapter;
import java.awt.event.MouseAdapter;
// public class SwitchControl extends MouseMotionAdapter {
public class SwitchControl extends MouseAdapter {
27
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
private DiceModel dm;
private SwitchView sv;
private boolean lr;
// public SwitchControl(SwitchView sView,
// DiceModel dModel, boolean leftright) {
public SwitchControl(SwitchView sView,
DiceModel dModel, boolean leftright) {
this.sv = sView;
this.dm = dModel;
this.lr = leftright;
}
// public void mouseMoved(MouseEvent me) {
public void mouseClicked(MouseEvent me) {
if ((sv.contains(me.getX(), me.getY())) &&
(dm.circle.contains(me.getX(), me.getY()))) {
dm.setSwitch(me.getX(), me.getY(), lr);
}
}
}
Die Methode SwitchControl() baut eine Beziehung zum Modell (die Klasse
DiceModel, Kapitel 4.2) und zuständigen View (die Klasse SwitchView, Kapitel
4.4) auf.
4.4. Das View, die Klasse SwitchView
Das in der Abbildung 11 dargestellte Diagramm in UML-Notation gehört zu der
View-Klasse SwitchView. Diese Klasse ist zuständig für die Darstellung der
gewünschten Einstellung der Schalter A und B.
Abbildung 11: View, die Klasse SwitchView
Quelle: eigene Darstellung
Die
Klasse
SwitchView
wird
von
der
Java-eigenen
Klasse
JPanel
(javax.swing.JPanel) abgeleitet und implementiert das Interface Observer. Bei der
Klasse JPanel handelt es sich um eine Art Container, der andere Komponenten
aufnimmt, um diese graphisch abzubilden.
28
Das Interface Observer dient der Überwachung der Änderungen, welche infolge
des Wechsels der Schalterstellung durch den Benutzer oder „automatisch“
entstehen. Diese Änderungen bekommt die Klasse als Wert übergeben und
aktualisiert dementsprechend die graphische Ausgabe.
Die Methode SwitchView stellt Verbindung zum Modell her und richtet das View
mittels addObserver() als Observer des Modells ein.
Die Methode update() ist für die Aktualisierung der Bildschirmdarstellung
zuständig. Diese erfolgt durch den Aufruf der Methode setSignal(). Die
notwendigen Daten werden vom Modell (durch Aufruf der Methode getSwitch())
abgerufen.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import javax.swing.JPanel;
import java.awt.Graphics;
import java.util.Observer;
import java.util.Observable;
public class SwitchView extends JPanel implements Observer {
private static final long serialVersionUID = -7140745252271819121L;
private DiceModel dm;
private int signal;
private double signalAngle;
private boolean lr;
public SwitchView(DiceModel dModel, boolean leftright) {
this.dm = dModel;
this.lr = leftright;
dm.addObserver(this);
signal = dm.startSwitch; // Default- Signal
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawOval(dm.zX - dm.rR, dm.zY - dm.rR, 2 * dm.rR, 2 * dm.rR);
g.drawString(dm.stringOne, dm.intXforOne, dm.intYforOne);
g.drawString(dm.stringTwo, dm.intXforTwo, dm.intYforTwo);
g.drawString(dm.stringTree, dm.intXforTree, dm.intYforTree);
signalAngle = (2 * Math.PI * signal / 3) - (Math.PI / 2);
g.drawLine(dm.zX, dm.zY, dm.zX + (int) ((dm.rR - 5) *
Math.cos(signalAngle)), dm.zY + (int) ((dm.rR - 5) *
Math.sin(signalAngle)));
g.dispose();
}
public void setSignal(int sig) {
this.signal = sig;
if (lr) {
signal = dm.getSwitch(dm.LEFT);
} else {
signal = dm.getSwitch(dm.RIGHT);
}
29
37
38
39
40
41
42
43
repaint();
}
public void update(Observable obs, Object obj) {
this.dm = (DiceModel) obs;
setSignal(signal);
}
}
Die Methode paintComponent() ist von JComponent (javax.swing.JComponent)
abgeleitet und ist für das Zeichnen der Komponente zuständig.
4.5. Das View, die Klasse LightsView
Das in der Abbildung 12 dargestellte Diagramm in UML-Notation gehört zu der
View-Klasse LightsView. Diese Klasse wird von der Java-eigenen Klasse Canvas
(java.awt.Canvas) abgeleitet. Sie implementiert das Interface Observer und ist für
die Darstellung der Lichtsignale in den Detektoren A und B zuständig.
Abbildung 12: View, die Klasse LightsView
Quelle: eigene Darstellung
„Die Klasse Canvas stellt einen einfachen Hintergrund dar, auf dem Bilder platziert
oder grafische Ausgaben gemacht werden können.“34 Um das zu erreichen, wurde
die
Methode
paint()
überschrieben.
Das
Interface
Observer
dient
der
Überwachung der Änderungen.
Die Methode LightsView stellt eine Verbindung zum Modell her und richtet das
View als Observer (durch addObserver()) des Modells ein.
Die Methode update() ist für die Aktualisierung der Bildschirmdarstellung
zuständig. Diese erfolgt durch den Aufruf der Methode setSignal(). Die
notwendigen Daten werden vom Modell durch Aufruf der Methode getLights()
abgerufen.
34 Middendorf u.a., Stand: 17.08.2006
30
Die Animation der Lichter zeigte ausgeprägtes Flackern während der Ausführung
einer Vielzahl der Experimente ohne Verzögerung. Dieses Flackern entsteht
dadurch, dass vor dem Aufruf der paint()-Methode „zunächst das Fenster gelöscht
wird und dadurch unmittelbar vor der Ausgabe des nächsten Bildes ganz kurz ein
vollständig leerer Hintergrund erscheint.“35 Um dieses Flackern zu reduzieren
wurde die zweite update()-Methode (Zeile 62) eingerichtet. Dadurch wurde
erreicht, dass bei einem Aufruf von repaint() in der Methode setSignal(), nicht
gleich paint(), sondern zunächst die Methode update() aufgerufen wird. Da die
Methode update() durch eine eigene Version überschrieben wird, die den
Hintergrund unverändert lässt, konnte das Flackern auf ein Minimum reduziert
werden.
Jedoch konnte das Flackern nicht vollständig eliminiert werden, daher wurde
zusätzlich der Doppelpufferung-Mechanismus (Zeilen 20, 21) angewendet. „Beim
Doppelpuffern
wird
Bildschirmausgabe
bei
in
ein
jedem
Animationsschritt
Offscreen-Image
zunächst
geschrieben.
die
Erst
gesamte
wenn
alle
Ausgabeoperationen abgeschlossen sind, wird dieses Offscreen-Image auf die
Fensteroberfläche kopiert.“36 Durch Doppelpuffering wird erreicht, dass das Bild
komplett neu aufgebaut ist, bevor es sichtbar wird.
...
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class LightsView extends Canvas implements Observer {
private static final long serialVersionUID = -8511530608735372306L;
private DiceModel dm;
private int signal;
private boolean lr;
public LightsView(DiceModel dModel, boolean leftright) {
this.dm = dModel;
this.lr = leftright;
dm.addObserver(this);
signal = dm.startLights; // Default- Signal
}
public void paint(Graphics g) {
BufferedImage theImage = new BufferedImage(this.getWidth(),
this.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics g1 = theImage.getGraphics();
Color oldColor = g.getColor();
g1.setColor(this.getBackground());
g1.fillRect(0, 0, getWidth(), getHeight());
g1.setColor(oldColor);
switch (signal) {
35 Krüger, 2003, S. 736
36 Krüger, 2003, S. 741
31
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
case 0:
paintLight(g1, dm.ENABLED, dm.DISABLED);
break;
case 1:
paintLight(g1, dm.DISABLED, dm.ENABLED);
break;
default:
paintLight(g1, dm.DISABLED, dm.DISABLED);
}
g.drawImage(theImage, 0, 0, getWidth(), getHeight(), null);
}
private void paintLight(Graphics g, boolean red, boolean green) {
g.drawRect(dm.zX - dm.bR, dm.zY - dm.hR, 2 * dm.bR, 2 * dm.hR);
g.setColor(dm.defco);
g.fillOval(dm.rX - dm.lR, dm.rY - dm.lR, 2 * dm.lR, 2 * dm.lR);
g.setColor(dm.defco);
g.fillOval(dm.gX - dm.lR, dm.gY - dm.lR, 2 * dm.lR, 2 * dm.lR);
if (red) {
g.setColor(dm.klick);
g.fillOval(dm.rX - dm.lR, dm.rY – dm.lR, 2 * dm.lR, 2 * dm.lR);
g.setColor(dm.defco);
g.fillOval(dm.gX - dm.lR, dm.gY – dm.lR, 2 * dm.lR, 2 * dm.lR);
} if (green) {
g.setColor(dm.defco);
g.fillOval(dm.rX - dm.lR, dm.rY – dm.lR, 2 * dm.lR, 2 * dm.lR);
g.setColor(dm.klack);
g.fillOval(dm.gX - dm.lR, dm.gY – dm.lR, 2 * dm.lR, 2 * dm.lR);
}
}
public void setSignal(int sig) {
this.signal = sig;
signal = dm.getLights(lr);
repaint();
}
public void update(Graphics g){
paint(g);
}
public void update(Observable obs, Object obj) {
this.dm = (DiceModel) obs;
setSignal(signal);
}
}
In Abhängigkeit von dem Signal, das von der Methode getLights() des Modells
geliefert
wird,
wird
in
dem
switch-case-Konstrukt
festgelegt,
welche
Lichterkombinationen angezeigt werden sollen. Aus diesem switch-case-Konstrukt
wird mit den entsprechenden Parametern die Methode paintLight() aufgerufen, die
dann das Zeichnen übernimmt.
In dieser Klasse wird (genau wie in der Klasse SwitchView, Kapitel 4.4) zwischen den
Detektoren A und B unterschieden.
32
4.6. Der Controller, die Klasse AlphaControl
Die Abbildung 33 zeigt das Diagramm der Controller-Klasse AlphaControl in UMLNotation. Diese Klasse ist für die Weitergabe des vom JSlider gelieferten Wertes
für Alpha an das Modell zuständig.
Abbildung 13: Controller, die Klasse AlphaControl
Quelle: eigene Darstellung
Die
Klasse
AlphaControl
implementiert
die
Interfaces
ChangeListener
(javax.swing.event.ChangeListener) und Observer.
Wenn der Wert von JSlider von dem Benutzer verändert wird, sendet JSlider ein
ChangeEvent (javax.swing.event.ChangeEvent) aus. Um auf dieses Ereignis zu
reagieren, wird das Interface ChangeListener implementiert. Dabei wird die
dazugehörige Methode stateChanged() aufgerufen, wenn Änderungen vorliegen.
Dadurch wird der ermittelte Wert über den Aufruf der setValueAlpha()-Methode an
das Modell übergeben.
Beim Implementieren der Funktionalität des „RESET“-Buttons ist aufgefallen, dass
der JSlider auf das Zurücksetzen nicht reagierte. Um das Zurücksetzen des
JSlider zu gewährleisten, wurde in dieser Klasse das Interface Observer
implementiert. Mittels der update()-Methode wird der Wert vom Modell bezogen (in
diesem Fall durch den Aufruf der Methode getValueAlpha()), konvertiert und
gesetzt.
01
02
03
04
05
06
07
08
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.util.Observable;
import java.util.Observer;
public class AlphaControl implements ChangeListener, Observer {
private DiceModel dm;
33
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
private int value;
private JSlider sl;
public AlphaControl(DiceModel dModel) {
this.dm = dModel;
dm.addObserver(this);
}
public void stateChanged(ChangeEvent ce) {
sl = (JSlider) ce.getSource();
if (sl.getValueIsAdjusting()) {
value = sl.getValue();
dm.setValueAlpha(value);
}
}
public void update(Observable obs, Object arg) {
this.dm = (DiceModel) obs;
if (sl != null) {
sl.setValue((int) (dm.getValueAlpha() * dm.alphaMax));
}
}
}
Analog zu dieser Klasse sind auch die Klassen DelayControl und LoopsControl
aufgebaut. Die Klasse DelayControl ist für die Weitergabe des vom JSlider dieser
Klasse gelieferten Wertes für die Verzögerung der Ausführungsgeschwindigkeit an
das Modell zuständig. Die Klasse LoopsControl übergibt den Wert für die Anzahl
der Experimente an das Modell.
4.7. Das View, die Klasse AlphaTextView
Folgendes Diagramm in UML-Notation gehört zu der Klasse AlphaTextView. Diese
Klasse ist für die Darstellung der vom JSlider gelieferten Werte als Text zuständig.
Abbildung 14: View, die Klasse AlphaTextView
Quelle: eigene Darstellung
Diese Klasse wird von der Java-eigenen Klasse JPanel (javax.swing.JPanel)
abgeleitet und sie implementiert das Interface Observer. In der Beschreibung der
Klasse SwitchView (Kapitel 4.4.) wurde bereits erläutert, worum es sich bei der
34
Klasse JPanel handelt und wozu das Interface Observer dient, daher wird darauf
nicht mehr eingegangen.
Die Ausgabe erfolgt als Text, dabei wird dieser vorher durch die Klasse
DecimalFormat (java.text.DecimalFormat) als String gemäß der Vorlage (Zeile 12)
formatiert. Die Formatierung ist notwendig, um der unschönen Ausgabe
vorzubeugen, welche durch variable Anzahl an Vor- und bzw. oder Nachkommastellen bei den Werten entstehen können. Der anzuzeigende Wert wird
durch den Aufruf von getValueAlpha() aus dem Modell bezogen.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import javax.swing.JLabel;
import javax.swing.JPanel;
import java.text.DecimalFormat;
import java.util.Observer;
import java.util.Observable;
public class AlphaTextView extends JPanel implements Observer {
private static final long serialVersionUID = -1744194831062161442L;
private DiceModel dm;
private JLabel output;
private double text;
private DecimalFormat df = new DecimalFormat("#0.0000");
public AlphaTextView(DiceModel dModel) {
this.dm = dModel;
text = dm.getValueAlpha();
dm.addObserver(this);
output = new JLabel("Value of Alpha: " + df.format(text));
add(output);
}
public void setTextView(double text) {
this.text = text;
text = dm.getValueAlpha();
output.setText("Value of Alpha: " + df.format(text));
}
public void update(Observable obs, Object v) {
this.dm = (DiceModel) obs;
setTextView(text);
}
}
Die Klassen DelayTextView und LoopsTextView sind analog aufgebaut. Klasse
DelayTextView gibt den Wert für die Verzögerung in Sekunden aus und die Klasse
LoopsTextView gibt die von dem Benutzer eingestellte bzw. gewünschte Anzahl
an Experimenten als Text graphisch aus.
35
4.8. Das View, die Klasse StatisticsView
Die Abbildung 15 zeigt das Diagramm in UML-Notation der Klasse StatisticsView.
Diese Klasse ist für die graphische Darstellung des prozentualen Wertes für
Häufigkeit der gleichen Farbsignale in den Detektoren A und B zuständig.
Abbildung 15: View, die Klasse StatisticsView
Quelle: eigene Darstellung
Die Klasse StatisticsView unterscheidet sich nicht wesentlich von der Klasse
AlphaTextView (Kapitel 4.7.). Der einzige Unterschied besteht darin, dass die
visuelle Ausgabe nicht als Text, sondern als Fortschrittsbalken in einer
JProgressBar erfolgt. Dabei wird der darzustellende Wert durch den Aufruf der
Methode getStatistics() aus dem Modell bezogen.
...
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class StatisticsView extends JPanel implements Observer {
private static final long serialVersionUID = 4410445127875722664L;
private DiceModel dm;
private JProgressBar stat;
private int value;
public StatisticsView(JProgressBar jpbS, DiceModel dModel) {
this.dm = dModel;
this.stat = jpbS;
dm.addObserver(this);
value = dm.getStatistics();
stat.setMinimum(dm.statisticsMin);
stat.setMaximum(dm.statisticsMax);
this.add(stat);
}
public void setStat(int val) {
this.value = val;
value = dm.getStatistics();
stat.setValue(value);
}
public void update(Observable obs, Object obj) {
this.dm = (DiceModel) obs;
setStat(value);
}
}
36
4.9. Der Controller, die Klasse ButtonControl
Das folgende Diagramm in UML-Notation zeigt die Klasse ButtonControl. Diese
Klasse reagiert auf das Betätigen der Buttons durch den Benutzer.
Abbildung 16: Controller, die Klasse ButtonControl
Quelle: eigene Darstellung
Durch das Betätigen eines Buttons durch den Benutzer wird die Klasse zum
Empfänger von „Action-Events“ und implementiert das Interface ActionListener
(java.awt.event.ActionListener). Dadurch bekommt die Klasse Ereignisse vom Typ
ActionEvent übergeben. „ActionEvent erweitert die Klasse AWTEvent und stellt
neben getID() und getSource() vor allem die Methode getActionCommand() zur
Verfügung, mit der die verschiedenen Ereignisquellen unterschieden werden
können.
[...]
Das
Interface
ActionListener
stellt
lediglich
die
Methode
actionPerformed() zur Verfügung, die beim Aufruf ein ActionEvent übergeben
bekommt.“37
Beim Betätigen des Buttons „START“ wird von dieser Klasse die Ausführung des
Threads im Modell in Gang gesetzt. Da die Methode run() niemals von dem
Programm direkt aufgerufen werden sollte, wird dazu in der Zeile 14 die Methode
start() aufgerufen.38
...
04
05
06
07
08
09
10
11
12
13
public class ButtonControl implements ActionListener {
private DiceModel dm;
private Thread th;
public ButtonControl(DiceModel dModel) {
this.dm = dModel;
}
public void actionPerformed(ActionEvent ae) {
th = new Thread(dm);
if (ae.getActionCommand() == dm.commandStart) {
dm.pd.setBStart();
37 Krüger, 2003, S. 632-633
38 Vgl. Krüger, 2003, S. 466
37
14
15
16
17
18
19
20
21
22
23
th.start();
} else if (ae.getActionCommand() == dm.commandStop) {
dm.pd.setBStop();
dm.stopAll();
} else if (ae.getActionCommand() == dm.commandReset) {
dm.pd.setBReset();
dm.resetAll();
}
}
}
4.10. Applet, die Klasse PlayDice
Folgendes Diagramm in UML-Notation zeigt die Klasse PlayDice. Die Klasse
PlayDice wird von der Klasse JApplet (javax.swing.JApplet) abgeleitet und ist für
den Aufbau des Applets zuständig.
Abbildung 17: Applet, die Klasse PlayDice
Quelle: eigene Darstellung
Die Klasse JApplet „erweitert java.applet.Applet um die Unterstützung der SwingArchitektur“39 und implementiert das RootPaneContainer-Interface. Dabei ist es
erforderlich, dass alle Komponenten an die ContentPane übergeben werden.40
Die Klasse Applet (java.applet.Applet) ist „die Basis für alle Java-Anwendungen,
die in HTML-Dokumente eingebunden werden sollen.“41 Die Abbildung 18 zeigt die
Ableitungshierarchie dieser Klasse.42
39
40
41
42
Middendorf u.a., Stand: 17.08.2006
Vgl. Krüger, 2003, S. 775
Middendorf u.a., Stand: 17.08.2006
Vgl. Krüger, 2003, S. 775
38
Abbildung 18: Ableitungsbaum der Applet-Klasse
Quelle: Krüger, 2003, S. 888
„Nach dem Laden wird das Applet zunächst instanziert und dann initialisiert.
Anschließend wird es gestartet, erhält GUI-Events und wird irgendwann wieder
gestoppt.“43 Zum Instanzieren wird der parameterlose Default-Konstruktor der
Klasse aufgerufen. Anschließend wird vom Browser die init()-Methode (Zeile 118)
aufgerufen und dadurch initialisiert.44
...
117
118
// Initialize Applet
public void init() {
...
Die Klasse Container (java.awt.Container, Zeile 194) dient dazu, „Steuerelemente
zu Fenstern oder Dialogen zusammenzufassen. Ein Exemplar von Container kann
verschiedene
Steuerelemente,
beispielsweise
Buttons
und
sogenannte
Scrollbars.“45
Komponenten,
Zunächst
wird
die
enthalten,
Methode
getContentPane() aufgerufen, diese gibt einen Container zurück. Auf dem
zurückgegebenen Container wird die Komponente per add() platziert (Zeilen 196198).46
...
194
195
196
197
198
Container cp = getContentPane();
cp.setLayout(new BorderLayout());
cp.add(BorderLayout.NORTH, pInscription);
cp.add(BorderLayout.CENTER, pLightsAndSwitches);
cp.add(BorderLayout.SOUTH, pStatisticsAndAlphaBeta);
...
Die Methoden setBStart(), setBStop() und setBReset() aktivieren und bzw. oder
43
44
45
46
Krüger, 2003, S. 889
Vgl. Krüger, 2003, S. 889
Middendorf u.a., Stand: 17.08.2006
Vgl. Krüger, 2003, S. 758
39
deaktivieren die einzelnen Buttons und Slider.
...
265
266
267
268
269
270
271
272
273
274
275
276
public void setBStart() {
if (dModel.getValueLoops() == dModel.loopsLimit) {
bStart.setEnabled(dModel.ENABLED);
bStop.setEnabled(dModel.DISABLED);
bReset.setEnabled(dModel.ENABLED);
} else if (dModel.getValueLoops() > dModel.loopsLimit) {
bStart.setEnabled(dModel.DISABLED);
bStop.setEnabled(dModel.ENABLED);
bReset.setEnabled(dModel.DISABLED);
slLoops.setEnabled(dModel.DISABLED);
}
}
...
4.11. Die Klasse InstructionSet
Das Diagramm in der Abbildung 19 zeigt die Klasse InstructionSet in UMLNotation. Die Klasse InstrictionSet definiert den Instruktionensatz.
Abbildung 19: Die Klasse InstructionSet
Quelle: eigene Darstellung
Die
einzelnen
Instruktionen
sind
in
einem
zwei-dimensionalen
Array
abgespeichert. Jede Instruktion besteht aus einer Kodierung, die angibt, welche
Farbe bei welcher Schalterstellung angezeigt werden soll. Dabei steht „R“ für rote
Farbe, „G“ für Grüne und „D“ für Default (entspricht Weiß) -Farben. Beispielsweise
die Kombination aus der Zeile 05: {„R“, „G“, „R“} bedeutet, dass bei der
Schalterposition auf 1 - rot, 2 – grün und 3 – rot ausgeben wird.
Die zwei apply()-Methoden in den Zeilen 14 und 18 ermöglichen das Abrufen der
gewünschten Instruktion in entsprechend benötigter Form.
01
02
03
04
05
06
07
08
public class InstructionSet {
protected String[][] colors = {
{"R", "R", "R"}, // 1. Instruction (0)
{"R", "R", "G"}, // 2. Instruction (1)
{"R", "G", "R"}, // 3. Instruction (2)
{"R", "G", "G"}, // 4. Instruction (3)
{"G", "R", "R"}, // 5. Instruction (4)
{"G", "R", "G"}, // 6. Instruction (5)
40
09
10
11
12
13
14
15
16
17
18
19
20
21
22
{"G", "G", "R"}, // 7. Instruction (6)
{"G", "G", "G"}, // 8. Instruction (7)
// Default for LIGHTS, only with RESET reachable
{"D", "D", "D"} // 9. Instruction (8)
};
protected Result apply(int instrNo, int switchL, int switchR) {
return new Result(switchL, switchR, colors[instrNo][switchL],
colors[instrNo][switchR]);
}
protected ResultSeparate apply(int instrNo, int switchSeparate) {
return new ResultSeparate(switchSeparate,
colors[instrNo][switchSeparate]);
}
}
4.12. Die Klasse Result
Die Abbildung 20 zeigt das Diagramm der Klasse Result in UML-Notation. Mittels
dieser Klasse wird festgestellt, bei welcher Schalterpostion an den Detektoren
welche Farbe ausgegeben werden muss.
Abbildung 20: Die Klasse Result.java
Quelle: eigene Darstellung
Der Aufruf der Methode Result() der gleichnamigen Klasse erfolgt von der
Methode run() vom Modell aus. Dabei werden die Nummer der Instruktion und die
Positionen der Schalter A und B übergeben. Zurückgeliefert wird die Information,
zu welcher Schalterstellung von A und B, welche Farbe jeweils ausgegeben
werden muss.
01
02
03
04
05
06
07
08
09
10
11
public class Result {
private int switchL; // position of Switch LEFT
private int switchR; // position of Switch RIGHT
protected String colorL; // Color LEFT
protected String colorR; // Color RIGHT
protected Result(int switchL, int switchR,
String colorL, String colorR) {
this.switchL = switchL;
this.switchR = switchR;
this.colorL = colorL;
this.colorR = colorR;
41
12
13
14
15
16
}
public String toString() {
return switchL + " " + switchR + " " + colorL + " " + colorR;
}
}
Diese Klasse ist notwendig, um festzustellen, ob in den Detektoren A und B die
gleiche Farbe ausgegeben wurde. Wenn die ausgegebenen Farben in den
Detektoren A und B gleich sind, wird der Zähler countLights im Modell
hochgezählt.
4.13. Die Klasse ResultSeparate
In der Abbildung 21 ist das Diagramm der Klasse ResultSeparate in UML-Notation
zu sehen. Diese Klasse zeigt an, welche Farbe bei welcher Schalterposition an
einem Detektor ausgeben wird.
Abbildung 21: Die Klasse ResultSeparate
Quelle: eigene Darstellung
Diese Klasse unterscheidet sich von der Klasse Result (Kapitel 4.12) darin, dass
die Information nur für einen der beiden Detektoren – A oder B zurückgeliefert
wird. Der Aufruf erfolgt ebenfalls vom Modell aus, allerdings von der Methode
setLights(). Die Methode setLights() ihrerseits wird von der Methode run() zwei
mal in Folge mit unterschiedlichen Parametern (getrennt für die Detektoren A und
B) aufgerufen. Die zurückgelieferten Informationen werden dazu verwendet, um
die Farben in den Detektoren zu setzen und graphisch auszugeben.
01
02
03
04
05
06
07
08
09
10
11
public class ResultSeparate {
protected int switchSeparate;
private String colorSeparate;
protected ResultSeparate(int switchSeparate, String colorSeparate) {
this.switchSeparate = switchSeparate;
this.colorSeparate = colorSeparate;
}
public String toString() {
return colorSeparate;
}
}
42
4.14. Die Klasse Simulation
Die Abbildung 22 zeigt das Diagramm der Klasse Simulation in UML-Notation. Die
Klasse Simulation simuliert das EPR-Experiment.
Abbildung 22: Die Klasse Simulation
Quelle: eigene Darstellung
Hierbei wird an zwei Stellen die Klasse Random (java.util.Random) verwendet: um
die Nummer der Instruktion auszuwürfeln und um die Position des Schalters A
oder B zu ermitteln. „Die Klasse Random kann Folgen von Pseudo-Zufallszahlen
erzeugen. Es können Zufallszahlen für alle Standarddatentypen angefordert
werden.“47
Die Methode chooseInstruction() bekommt den vom Benutzer eingestellten Wert
Alpha übergeben und führt in Abhängigkeit von diesem Wert und ausgewürfelter
Instruktionsnummer die im Kapitel 2.3. beschrieben Berechnungen durch. Dabei
wird die Nummer der Instruktion (0 bis 7) an das Modell zurückgeliefert.
Die Methode chooseSwitch() wird nur bei mehr als einem Experiment von der
run()- Methode des Modells aufgerufen. Hierbei wird die Position des Schalters 0, 1 oder 2 ausgewürfelt und zurückgeben, welche entsprechend der
Schalterpositionen als 1, 2 oder 3 dem Benutzer angezeigt werden. Diese
Methode wird zwei mal in Folge aufgerufen, um die Position der Schalter A und B
separat zu ermitteln.
01
02
03
04
05
import java.util.Random;
public class Simulation {
private Random rdSwitchPs = new Random();
private Random rdInstrSet = new Random();
47 Middendorf u.a., Stand: 17.08.2006
43
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
private int nbOfInstr; // should be attribute of InstructionSet
private int nbOfSwPos;
protected InstructionSet instrSet;
protected Simulation(InstructionSet instrSet) {
this.instrSet = instrSet;
this.nbOfInstr = instrSet.colors.length - 1; // = 8
this.nbOfSwPos = instrSet.colors[0].length; // = 3
}
protected int chooseInstruction(double alpha) {
// Precondition: 0 < alpha < 1
double p = rdInstrSet.nextDouble();
double val;
double beta = 1 - alpha;
if (0 <= p && p < beta / 2) {
val = 2 * p / beta;
} else if (beta / 2 <= p && p < 1 - beta / 2) {
val = 6 * (p - 0.5) / alpha + 4;
} else {
val = 2 * (p - 1) / beta + 8;
}
if (val >= nbOfInstr) {
// not reachable
System.err.println("Simulation.chooseInstruction(): ERROR!");
}
return (int) Math.floor(val);
}
protected int chooseSwitch() {
double p = rdSwitchPs.nextDouble();
return (int) Math.floor(p * nbOfSwPos);
}
}
44
5. Zusammenfassung
Das Ziel dieser Arbeit bestand in der Entwicklung eines Programms zur
Visualisierung des EPR-Experiments nach N. David Mermin. Dafür wurden
zunächst
die
theoretischen
Grundlagen
erläutert.
Dabei
wurden
die
Beschreibung
des
quantenmechanische und mathematische Zusammenhänge erklärt.
Die
Grundlage
für
Programmentwicklung
bildete
die
Experiments von Mermin. Daraus wurden auch die Anforderungen für Aufbau
abgeleitet. Die Umsetzung erfolgte in Java (Version 5.0) als Applet nach dem
MVC-Prinzip. Weiterhin wurde Swing verwendet, weil es eine Reihe an Vorteilen
gegenüber Abstract Windowing Toolkit (AWT) wie z.B. die Möglichkeit komplexe
graphische Oberflächen zu konstruieren oder Fähigkeit sich an die Fähigkeiten der
jeweiligen Plattform anzupassen. Manche von den eingesetzten Komponenten
erforderten den Einsatz von Java 2D-API, welche komplexe Grafikoperationen und
Routinen zur Bildbearbeitung zur Verfügung stellt. Als Entwicklungsumgebung
wurde Eclipse SDK 3.1.x verwendet. Zur Erstellung der UML-Diagramme wurde
NetBeans (Enterprise Pack 5.5 Beta) herangezogen.
Die vorgelegte Arbeit beinhaltet eine detaillierte Beschreibung der angewandten
Klassen und Methoden. Zum besseren Verständnis wurden die Erklärungen durch
Quellcode, Tabellen und Abbildungen ergänzt.
Das Programm wurde während der Implementierung iterativ getestet. Dazu
wurden vorübergehend Funktionen verwendet, die die Ausgabe auf die Konsole
umgeleitet haben. Anhand der Anforderungsanalyse wurden Tests erstellt und
durchgeführt. Dabei wurde die ist-Ausgabe mit der soll-Ausgabe verglichen. Bei
einer festgestellten Abweichung wurde nach deren Ursache gesucht und diese
beseitigt bzw. korrigiert. Danach wurde der Testlauf wiederholt. Der Vorgang
wurde iterativ fortgesetzt, bis das gewünschte Ergebnis erreicht war. Diese
Ausgabefunktionen
wurden
aus
der
fertigen
Anwendung
entfernt.
Die
durchgeführten Tests bescheinigten den korrekten und stabilen Betrieb der
Anwendung,
sowie
die
Erfüllung
aller
Anforderungen.
45
an
das
Programm
gestelleten
6. Ausblick
Das
Erweiterungspotenzial
des
Programms
ist
bei
weitem
noch
nicht
ausgeschöpft. Zur weiteren Entwicklung ist es vorstellbar, das Programm um
Funktionalität zur Speicherung der Ergebnisse der durchgeführten Experimente zu
erweitern. Dabei könne die Ergebnisse beispielsweise in einer Tabelle abspeichert
werden. Diese Funktion ermöglicht dem Anwender die so gewonnenen Daten
eventuell mit einem Parser auszulesen und die Ergebnisse weiter zu verwerten.
Als eine mögliche Verwendung der gewonnenen Ergebnisse ist die Verifikation
anhand der mathematischen Berechnung vorstellbar, der zu Anfang der Arbeit
erwähnten Wahrscheinlichkeiten.
Weiterhin kann das Programm um eine Anzeige zur Darstellung des gerade
ablaufenden Experimentes erweitert werden. Dadurch kann der Benutzer nicht nur
erkennen, an welchem Experiment das Programm gerade arbeitet, sondern auch
abschätzen, wie lange es noch dauert, bis es fertig ist. Weitere Möglichkeit ist die
Restdauer als Zeit anzuzeigen. Da diese von einem Rechner zum anderen
unterschiedlich ausfallen kann, ist dies mittels fester Umrechnung nicht
realisierbar. Die Lösung kann so aussehen, dass das Programm die Dauer der
Ausführung bestimmter (mindest-) Anzahl an Experimenten misst und daraus die
Restdauer berechnet. Die Restadauer sollte während der Ausführung der
Experimente laufend aktualisiert werden.
Daraus kann auch eine etwas andere Modifikation abgeleitet werden – der
Anwender stellt die gewünschte Dauer der Experimente in Minuten ein. Daraus
berechnet das Programm selbst, wie viele Experimente es durchführen kann.
Selbstverständlich muss auch hierbei sichergestellt werden, dass diese Anzahl
während des Programmablaufs laufend aktualisiert wird. Möglicher Einsatzzweck
des Programms mit derartiger Modifikation ist beispielsweise das Vorführen des
Experimentes bei einer Präsentation oder Vorlesung.
Denkbar ist auch die Ergänzung der Bedienungsfunktionalität um Bedienung mit
der Tastatur, z.B. Slider per Focus-Umschaltung mit der Tastatur einzustellen.
Dadurch kann höhere Präzision bei den Einstellungen erreicht werden.
46
Literaturverzeichnis
Filk, 2004: Grundlagen und Probleme der Quantenmechanik. Online im Internet.
URL: http://idefix.physik.uni-freiburg.de/~aufgabe/Skripte/Grundlagen.pdf
Stand: 17.08.2006
FWF, 2004: Kurzbeschreibung des Projekts. Online im Internet.
URL: http://www.fwf.ac.at/de/abstracts/abstract.asp?L=D&PROJ=L135
Stand: 17.08.2006
Götz, 2003: Das EPR-Paradoxon und die Bell'sche Ungleichung. Online im Internet.
URL: http://www.ikg.rt.bw.schule.de/qphfbmat/epr.pdf
Stand: 17.08.2006
Iliopoulos, 2003: Quantenkryptographie Teil 2. Online im Internet.
URL: http://www.cip.physik.uni-muenchen.de/~iliopoul/Ausarbeitung2.pdf
Stand: 17.08.2006
Jung, 2003: Einstein-Podolsky-Rosen-Experimente. Online im Internet.
URL: http://www.bistr-o-mathik.org/resources/files/seminars/epr.pdf
Stand: 17.08.2006
Krüger, 2003: Handbuch der Java-Programmierung. München
Lehle, 1997: Visualisierung in der Relativitätstheorie.Online im Internet.
URL: http://www.tat.physik.uni-tuebingen.de/~lehle/diss-97.pdf
Stand: 17.08.2006
Meißner, 2002: Anforderungsanalyse. Online im Internet.
URL: http://www.tfh-berlin.de/~lmeissne/WS02/ch03.pdf
Stand: 17.08.2006
Meiler, o.J.: Einführung in die objektorientierte Programmierung (MVC). Online im
Internet. URL: http://http://www.informatik.unileipzig.de/~meiler/Java.dir/JavaWS05.dir/Vorlesung/V13.pdfsung/V13.pdf
Stand: 17.08.2006
Mermin, 1985: Is the moon there when nobody looks? Reality and the quantum theory. IN:
PHYSICS TODAY. Online im Internet.
URL: http://www.physics.iitm.ac.in/~arvind/ph350/mermin.pdf
Stand: 17.08.2006
47
Middendorf u.a., 2002: JavaTM. Programmierhandbuch und Referenz für die JavaTM-2Plattform. Online im Internet.
URL: http://www.dpunkt.de/java/
Stand: 17.08.2006
Rüdiger,
2004:
Quantenkryptographie.
Vortrag
im
Rahmen
der
Vortragsreihe
Wissenschaft trifft Wirtschaft. Online im Internet.
URL: http://public.fh-wolfenbuettel.de/~ruediger/talks/VortragQuCrypt.041130.pdf
Stand: 17.08.2006
Tillemans, 2004: Beam mich zum anderen Ufer, Scotty! Wiener Physikern gelingt die
Quantenteleportation von Photonen über die Donau. Online im Internet.
URL: http://www.einsteingalerie.de/aktuell/quantenteleportation.html.
Stand: 17.08.2006
Ullenboom, 2005.: Java ist auch eine Insel. Programmieren für die Java 2-Plattform in der
Version 5. Online im Internet.
URL: http://www.galileocomputing.de/openbook/javainsel5/javainsel01_000.htm
Stand: 17.08.2006
Wallenborn, 1999: Herr Einstein, Herr Podolski und Herr Rosen. Online im Internet.
URL: http://theory.gsi.de/~vanhees/faq-pdf/epr.pdf.
Stand: 17.08.2006
Wikipedia: Anforderungsanalyse. Online im Internet.
URL: http://de.wikipedia.org/wiki/Anforderungsanalyse
Stand: 17.08.2006
Wikipedia: Applet. Online im Internet.
URL: http://de.wikipedia.org/wiki/Applet.
Stand: 17.08.2006
Zeilinger: Die Spukhaftigkeit der Realität. Online im Internet.
URL: http://www.project-syndicate.org/commentary/zeilinger1/German
Stand: 17.08.2006
48
Eidesstattliche Erklärung
Ich erkläre hiermit an Eides Statt, dass ich die vorliegende Arbeit selbständig und
ohne Benutzung anderer als der angegebenen Hilfsmittel angefertigt habe; die aus
fremden Quellen direkt oder indirekt übernommenen Gedanken sind als solche
kenntlich gemacht. Die Arbeit wurde bisher in gleicher oder ähnlicher Form keiner
anderen Prüfungsbehörde vorgelegt und auch noch nicht veröffentlicht.
__________________________
_______________________
Ort, Datum
Unterschrift
49
Anhang
50
Quellcode
AlphaControl.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.util.Observable;
import java.util.Observer;
public class AlphaControl implements ChangeListener, Observer {
private DiceModel dm;
private int value;
private JSlider sl;
public AlphaControl(DiceModel dModel) {
this.dm = dModel;
dm.addObserver(this);
}
public void stateChanged(ChangeEvent ce) {
sl = (JSlider) ce.getSource();
if (sl.getValueIsAdjusting()) {
value = sl.getValue();
dm.setValueAlpha(value);
}
}
public void update(Observable obs, Object arg) {
this.dm = (DiceModel) obs;
if (sl != null) {
sl.setValue((int) (dm.getValueAlpha() * dm.alphaMax));
}
}
}
AlphaTextView.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
import javax.swing.JLabel;
import javax.swing.JPanel;
import java.text.DecimalFormat;
import java.util.Observer;
import java.util.Observable;
public class AlphaTextView extends JPanel implements Observer {
private static final long serialVersionUID = -1744194831062161442L;
private DiceModel dm;
private JLabel output;
private double text;
private DecimalFormat df = new DecimalFormat("#0.0000");
public AlphaTextView(DiceModel dModel) {
this.dm = dModel;
text = dm.getValueAlpha();
dm.addObserver(this);
output = new JLabel("Value of Alpha: " + df.format(text));
add(output);
}
51
20
21
22
23
24
25
26
27
28
29
public void setTextView(double text) {
this.text = text;
text = dm.getValueAlpha();
output.setText("Value of Alpha: " + df.format(text));
}
public void update(Observable obs, Object v) {
this.dm = (DiceModel) obs;
setTextView(text);
}
}
ButtonControl.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class ButtonControl implements ActionListener {
private DiceModel dm;
private Thread th;
public ButtonControl(DiceModel dModel) {
this.dm = dModel;
}
public void actionPerformed(ActionEvent ae) {
th = new Thread(dm);
if (ae.getActionCommand() == dm.commandStart) {
dm.pd.setBStart();
th.start();
} else if (ae.getActionCommand() == dm.commandStop) {
dm.pd.setBStop();
dm.stopAll();
} else if (ae.getActionCommand() == dm.commandReset) {
dm.pd.setBReset();
dm.resetAll();
}
}
}
Config.java
001 import java.awt.Color;
002 import java.awt.geom.Ellipse2D;
003
004 public interface Config {
005
// Rechts und Links unterscheiden
006
static final boolean LEFT = true;
007
// Rechts und Links unterscheiden
008
static final boolean RIGHT = false;
009
// Etwas zu aktivieren
010
static final boolean ENABLED = true;
011
// Etwas zu deaktivieren
012
static final boolean DISABLED = false;
013
// Berechnung von Abstaenden
014
static final int diffXY = 5;
015
// x- Koordinate der Panelmitte
016
static final int zX = 100;
52
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
046
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
// y- Koordinate der Panelmitte
static final int zY = 100;
// Radius eines Kreises
static final int rR = 75;
// Halbe Breite eines Rechtecks
static final int bR = 50;
// Halbe Hoehe eines Rechtecks
static final int hR = 85;
// Hoehe der Buttons
static final int hB = 25;
// Breite der Buttons
static final int wB = 75;
// x- Koordinate des Rotlichts
static final int rX = 100;
// y- Koordinate des Rotlichts
static final int rY = 60;
// x- Koordinate des Gruenlichts
static final int gX = 100;
// y- Koordinate des Gruenlichts
static final int gY = 140;
// Radius der Lichter
static final int lR = 35;
// Laenge des Zeigers
static final double lP = 0.95;
// Noch gueltiger Radius
static final double rV = 1.20;
// Anzahl der Bereiche in die der Kreis eingeteilt wurde
static final int parts = 3;
// Umfang des Kreises im Bogenmas
static final double sphere = 2 * Math.PI;
// Abtastbereich verschieben
static final double shiftScan = 5 * Math.PI / 6;
// Zeichenbereich verschieben
static final double shiftDraw = Math.PI / 2;
// Maximaler Wert fuer slLoops
static final int loopsMin = 1;
// Maximaler Wert fuer slLoops
static final int loopsMax = 100000;
// Maximaler Wert fuer slDelay
static final int delayMin = 0;
// Maximaler Wert fuer slDelay
static final int delayMax = 2000;
// Variable um Sekunden in double zu berechnen
static final int delaySec = 1000;
// Minimaler Wert fuer pbStatistics
static final int statisticsMin = 0;
// Maximaler Wert fuer pbStatistics
static final int statisticsMax = 100;
// Wert um Statistk zurueckzusetzen
static final int resetStatCC = 0;
// Wert um Statistk zurueckzusetzen
static final int resetStatCL = 0;
// Minimaler Wert fuer slAlphaBeta
static final int alphaMin = 0;
// Maximaler Wert fuer slAlphaBeta
53
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
static final int alphaMax = 1000;
// Startwert fuer LOOPS
static final int startLoops = 1;
// GrenzWert fuer LOOPS
static final int loopsLimit = 1;
// Startwert fuer DELAY
static final int startDelay = 1500;
// Startwert fuer ALPHA
static final int startAlpha = 500;
// Startwert fuer SWITCH
static final int startSwitch = 0;
// Startwert fuer LIGHTS
static final int startLights = 2;
// Defaultwert fuer LIGHTS
static final int defaultLights = 8;
// Anzahl der Klicks UND Schleifen die ausgefuehrt wurden
static final int countClicks = 0;
// Anzahl der gleichen Lichter Links UND Rechts Gesamt
static final int countLights = 0;
// Circle
static final Ellipse2D circle = new Ellipse2D.Double(zX - rR * rV,
zY - rR * rV, 2 * rR * rV, 2 * rR * rV);
// Color, RED
static final Color klick = Color.RED;
// Color, GREEN
static final Color klack = Color.GREEN;
// Color, WHITE, default
static final Color defco = Color.WHITE;
// Color, BLACK, rectangle
static final Color rectc = Color.BLACK;
// Beschriftung, die Zahl 1
static final String stringOne = "1";
// Beschriftung, die Zahl 2
static final String stringTwo = "2";
// Beschriftung, die Zahl 3
static final String stringTree = "3";
// Variable zur Berechnung des Kreises, Position fuer Zahl 1
static final int intOne = 0;
// Variable zur Berechnung des Kreises, Position fuer Zahl 2
static final int intTwo = 1;
// Variable zur Berechnung des Kreises, Position fuer Zahl 3
static final int intTree = 2;
// Variable zur Berechnung des Kreises, Position fuer Zahl 1
static final double doubleOne = (2 * Math.PI *
intOne / 3) - (Math.PI / 2);
// Variable zur Berechnung des Kreises, Position fuer Zahl 2
static final double doubleTwo = (2 * Math.PI *
intTwo / 3) - (Math.PI / 2);
// Variable zur Berechnung des Kreises, Position fuer Zahl 3
static final double doubleTree = (2 * Math.PI *
intTree / 3) - (Math.PI / 2);
// Berechnung des Abstandes der Beschriftung vom Kreismittelpunkt
static final int intValDia = 2 * rR;
// Berechnung des Abstandes der Beschriftung vom Rand des Kreises
static final int intValRad = rR / 5;
54
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
170
180
181
// X-Koordinate fuer die Beschriftung mit fer Zahl 1
static final int intXforOne = zX;
// Y-Koordinate fuer die Beschriftung mit fer Zahl 1
static final int intYforOne = zY - (int) ((rR - intValDia diffXY) * Math.sin(doubleOne));
// X-Koordinate fuer die Beschriftung mit fer Zahl 2
static final int intXforTwo = zY - (int) ((rR - intValDia ((3 + (2 * diffXY)) * diffXY)) * Math.sin(doubleTwo));
// Y-Koordinate fuer die Beschriftung mit fer Zahl 2
static final int intYforTwo = zY + (int) ((rR + intValRad) *
Math.sin(doubleTwo));
// X-Koordinate fuer die Beschriftung mit fer Zahl 3
static final int intXforTree = zX - (int) ((rR - intValDia (3 * diffXY)) * Math.cos(doubleTree));
// Y-Koordinate fuer die Beschriftung mit fer Zahl 3
static final int intYforTree = zY + (int) ((rR + intValRad) *
Math.sin(doubleTree));
// Beschriftung des Butons START
static final String stringStart = "START";
// Beschriftung des Butons STOP
static final String stringStop = "STOP";
// Beschriftung des Butons RESET
static final String stringReset = "RESET";
// ActionCommand des Butons START
static final String commandStart = "Run";
// ActionCommand des Butons STOP
static final String commandStop = "Hold";
// ActionCommand des Butons RESET
static final String commandReset = "Res";
// Font for Inscription
static final String fontFont = "SansSerif";
// Dimension of Font, Big
static final int fontBig = 16;
// Dimension of Font, Middle
static final int fontMiddle = 14;
// Dimension of Font, Small
static final int fontSmall = 12;
// ToolTip fuer den Button START
static final String sToolTipStart =
new String("Press the button to run this program");
// ToolTip fuer den Button STOP
static final String sToolTipStop =
new String("Press the button to stop this program");
// ToolTip fuer den Button RESET
static final String sToolTipReset =
new String("Press the button to reset this program");
// ToolTip fuer den Slider LOOPS
static final String sToolTipLoops =
new String("Move to change the number of experiments");
// ToolTip fuer den Slider DELAY
static final String sToolTipDelay =
new String("Move to change the value of delay");
// ToolTip fuer den Slider ALPHA
static final String sToolTipAlpha =
new String("Move to change the value of Alpha");
55
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205 }
// ToolTip fuer Switches
static final String sToolTipSwitches = new String
("Click on the area next to a number to change the pointer");
// ToolTip fuer das ProgressBar Statistics
static final String sToolTipStatistics = new String
("Shows how often similar lights apperance on both sides");
// Label fuer die Bezeichnung
static final String inscriptionTerm =
new String("Animation of Mermin's EPR-Experiment");
// Label fuer die Quelle
static final String inscriptionSource =
new String("PHYSICS TODAY / APRIL 1985 PAG. 38-47");
// Label fuer den Urheber
static final String inscriptionDeveloper =
new String("(C) 2006 Heinrich Östreich, Roland Rüdiger");
// Label fuer LoopsTextView
static final String sLoops = new String("Number of Experiments: ");
// Label fuer DelayTextView
static final String sDelay = new String("Delay: ");
// Label fuer DelayTextView
static final String sSecond = new String(" second");
// Label fuer AlphaTextView
static final String sAlpha = new String("Value of Alpha: ");
DelayControl.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.util.Observable;
import java.util.Observer;
public class DelayControl implements ChangeListener, Observer {
private DiceModel dm;
private int value;
private JSlider sl;
public DelayControl(DiceModel dModel) {
this.dm = dModel;
dm.addObserver(this);
}
public void stateChanged(ChangeEvent ce) {
sl = (JSlider) ce.getSource();
if (sl.getValueIsAdjusting()) {
value = sl.getValue();
dm.setValueDelay(value);
}
}
public void update(Observable obs, Object arg) {
this.dm = (DiceModel) obs;
if (sl != null) {
sl.setValue(dm.getValueDelay());
}
}
}
56
DelayTextView.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import javax.swing.JLabel;
import javax.swing.JPanel;
import java.text.DecimalFormat;
import java.util.Observer;
import java.util.Observable;
public class DelayTextView extends JPanel implements Observer {
private static final long serialVersionUID = -1365880714846853979L;
private DiceModel dm;
private JLabel output;
private double text;
private DecimalFormat df = new DecimalFormat("#0.000");
public DelayTextView(DiceModel dModel) {
this.dm = dModel;
text = (double) (dm.delayMax - dm.getValueDelay()) / dm.delaySec;
dm.addObserver(this);
output = new JLabel("Delay: " + df.format(text) + dm.sSecond);
add(output);
}
public void setTextView(double text) {
this.text = text;
text = (double) (dm.delayMax - dm.getValueDelay()) / dm.delaySec;
output.setText("Delay: " + df.format(text) + dm.sSecond);
}
public void update(Observable obs, Object v) {
this.dm = (DiceModel) obs;
setTextView(text);
}
}
DiceModel.java
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
import java.awt.Color;
import java.awt.Dimension;
import java.awt.geom.Ellipse2D;
import java.util.Observable;
public class DiceModel extends Observable implements Runnable {
// Damit man auf die Buttons in PlayDice.java zugreifen kann
protected PlayDice pd;
// Variable um Rechts und Links zu unterscheiden
protected final boolean LEFT = Config.LEFT;
// Variable um Rechts und Links zu unterscheiden
protected final boolean RIGHT = Config.RIGHT;
// Variable um etwas zu aktivieren
protected final boolean ENABLED = Config.ENABLED;
// Variable um etwas zu deaktivieren
protected final boolean DISABLED = Config.DISABLED;
// Color, RED
protected final Color klick = Config.klick;
// Color, GREEN
protected final Color klack = Config.klack;
// Color, WHITE, default
57
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
protected final Color defco = Config.defco;
// Color, BLACK, rectangle
protected final Color rectc = Config.rectc;
// x- Kooridnate der Kreismitte
protected final int zX = Config.zX;
// y- Kooridnate der Kreismitte
protected final int zY = Config.zY;
// Radius eines Kreises
protected final int rR = Config.rR;
// Halbe Breite eines Rechtecks
protected final int bR = Config.bR;
// Halbe Hoehe eines Rechtecks
protected final int hR = Config.hR;
// Hoehe der Buttons
protected final int hB = Config.hB;
// Breite der Buttons
protected final int wB = Config.wB;
// x- Koordinate des Rotlichts
protected final int rX = Config.rX;
// y- Koordinate des Rotlichts
protected final int rY = Config.rY;
// x- Koordinate des Gruenlichts
protected final int gX = Config.gX;
// y- Koordinate des Gruenlichts
protected final int gY = Config.gY;
// Radius der Lichter
protected final int lR = Config.lR;
// Laenge des Zeigers
protected static final double lP = Config.lP;
// Noch gueltiger Radius
protected static final double rV = Config.rR;
// Abtastbereich verschieben
protected static final double shiftS = Config.shiftScan;
// Zeichenbereich verschieben
protected static final double shiftD = Config.shiftDraw;
// Minimaler Wert fuer slLoops
protected final int loopsMin = Config.loopsMin;
// Maximaler Wert fuer slLoops
protected final int loopsMax = Config.loopsMax;
// Minimaler Wert fuer slDelay
protected final int delayMin = Config.delayMin;
// Maximaler Wert fuer slDelay
protected final int delayMax = Config.delayMax;
// Variable um Sekunden in double zu berechnen
protected final int delaySec = Config.delaySec;
// Minimaler Wert fuer pbStatistics
protected final int statisticsMin = Config.statisticsMin;
// Maximaler Wert fuer pbStatistics
protected final int statisticsMax = Config.statisticsMax;
// Wert um Statistk zurueckzusetzen
private final int resetStatCC = Config.resetStatCC;
// Wert um Statistk zurueckzusetzen
private final int resetStatCL = Config.resetStatCL;
// Minimaler Wert fuer slAlphaBeta
protected final int alphaMin = Config.alphaMin;
58
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Maximaler Wert fuer slAlphaBeta
protected final int alphaMax = Config.alphaMax;
// Circle
protected final Ellipse2D circle = Config.circle;
// Beschriftung, die Zahl 1
protected final String stringOne = Config.stringOne;
// Beschriftung, die Zahl 2
protected final String stringTwo = Config.stringTwo;
// Beschriftung, die Zahl 3
protected final String stringTree = Config.stringTree;
// X-Koordinate fuer die Beschriftung mit fer Zahl 1
protected final int intXforOne = Config.intXforOne;
// Y-Koordinate fuer die Beschriftung mit fer Zahl 1
protected final int intYforOne = Config.intYforOne;
// X-Koordinate fuer die Beschriftung mit fer Zahl 2
protected final int intXforTwo = Config.intXforTwo;
// Y-Koordinate fuer die Beschriftung mit fer Zahl 2
protected final int intYforTwo = Config.intYforTwo;
// X-Koordinate fuer die Beschriftung mit fer Zahl 3
protected final int intXforTree = Config.intXforTree;
// Y-Koordinate fuer die Beschriftung mit fer Zahl 3
protected final int intYforTree = Config.intYforTree;
// Startwert fuer LOOPS
private int valueLoops = Config.startLoops;
// GrenzWert fuer LOOPS
protected final int loopsLimit = Config.loopsLimit;
// Startwert fuer DELAY
private int valueDelay = Config.startDelay;
// Startwert fuer ALPHA
private int valueAlpha = Config.startAlpha;
// Startwert fuer DELAY
protected final int startDelay = Config.startDelay;
// Startwert fuer LOOPS
protected final int startLoops = Config.startLoops;
// Startwert fuer ALPHA
protected final int startAlpha = Config.startAlpha;
// Startwert fuer ALPHA
private double valAlpha = (double) valueAlpha / (double) alphaMax;
// ** Inscription
// Beschriftung des Butons START
protected final String stringStart = Config.stringStart;
// Beschriftung des Butons STOP
protected final String stringStop = Config.stringStop;
// Beschriftung des Butons RESET
protected final String stringReset = Config.stringReset;
// ActionCommand des Butons START
protected final String commandStart = Config.commandStart;
// ActionCommand des Butons STOP
protected final String commandStop = Config.commandStop;
// ActionCommand des Butons RESET
protected final String commandReset = Config.commandReset;
// Font for Inscription
protected final String fontFont = Config.fontFont;
// Dimension of Font, Big
protected final int fontBig = Config.fontBig;
59
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
// Dimension of Font, Middle
protected final int fontMiddle = Config.fontMiddle;
// Dimension of Font, Small
protected final int fontSmall = Config.fontSmall;
// ToolTip fuer den Button START
protected final String sToolTipStart = Config.sToolTipStart;
// ToolTip fuer den Button STOP
protected final String sToolTipStop = Config.sToolTipStop;
// ToolTip fuer den Button RESET
protected final String sToolTipReset = Config.sToolTipReset;
// ToolTip fuer den Slider LOOPS
protected final String sToolTipLoops = Config.sToolTipLoops;
// ToolTip fuer den Slider DELAY
protected final String sToolTipDelay = Config.sToolTipDelay;
// ToolTip fuer den Slider ALPHA
protected final String sToolTipAlpha = Config.sToolTipAlpha;
// ToolTip fuer Switches
protected final String sToolTipSwitches = Config.sToolTipSwitches;
// ToolTip fuer das ProgressBar Statistics
protected final String sToolTipStatistcs = Config.sToolTipStatistics;
// Label fuer die Bezeichnung
protected final String inscriptionTerm = Config.inscriptionTerm;
// Label fuer die Quelle
protected final String inscriptionSource = Config.inscriptionSource;
// Label fuer den Urheber
protected final String inscriptionDeveloper =
Config.inscriptionDeveloper;
// Label fuer LoopsTextView
protected final String sLoops = Config.sLoops;
// Label fuer DelayTextView
protected final String sDelay = Config.sDelay;
// Label fuer DelayTextView
protected final String sSecond = Config.sSecond;
// Label fuer AlphaTextView
protected final String sAlpha = Config.sAlpha;
// ** Variables in setSwitch()
// Ankathete = Kosinus
private static double adjacent;
// Gegenkathete = Sinus
private static double opposite;
// Hypotenuse
private static double hypotenuse;
// Winkel unter dem der Mausklick stattfand
private static double angleXY;
// Umfang des Kreises im Bogenmas
private static double sphere = Config.sphere;
// Kosinus- Berechnung
private static double angle;
// Abtastbereich verschieben
private static double shiftScan = 5 * Math.PI / 6;
// Anzahl der Bereiche in die der Kreis eingeteilt wurde
protected static final int parts = Config.parts;
// ** Variables in setStatistics
private int statisticsAverage = statisticsMin;
// ** Variables in setLights()
60
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
// Startwert fuer SWITCH Left
private int signalSwitchLeft = Config.startSwitch;
// Startwert fuer SWITCH Right
private int signalSwitchRight = Config.startSwitch;
// Startwert fuer LIGHTS Left
private int signalLightsLeft = Config.startLights;
// Startwert fuer LIGHTS Right
private int signalLightsRight = Config.startLights;
// Startwert fuer SWITCH
protected final int startSwitch = Config.startSwitch;
// Startwert fuer LIGHTS
protected final int startLights = Config.startLights;
// Defaultwert fuer LIGHTS
private static final int defaultLights = Config.defaultLights;
// ** Variables for setStop
// STOP, boolean
private boolean stop;
// ** Variables in run()
// ALPHA
private static double alpha;
// LOOPS
private static int loops;
// Anzahl der Klicks UND Schleifen die ausgefuehrt wurden
private int countClicks = Config.countClicks;
// Anzahl der gleichen Lichter Links UND Rechts Gesamt
private int countLights = Config.countLights;
// ** Constructor
protected DiceModel(PlayDice pd){
this.pd = pd;
}
final protected void stopAll() {
setStop(true);
notificationOfChange();
}
final protected void resetAll() {
setValueAlpha(startAlpha);
setValueLoops(startLoops);
setValueDelay(startDelay);
setStatistics(resetStatCC, resetStatCL);
setCountClicks(resetStatCC);
setCountLights(resetStatCL);
setLights(defaultLights, startSwitch, LEFT);
setLights(defaultLights, startSwitch, RIGHT);
notificationOfChange();
}
final protected void setStop(boolean value) {
this.stop = value;
}
final protected boolean getStop() {
return stop;
}
final protected Dimension getPreferredSize() {
return new Dimension(wB, hB);
}
final protected void setSwitch (int sourceX,
61
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
int sourceY, boolean lr) {
adjacent = sourceX - zX;
opposite = zY - sourceY;
hypotenuse = Math.sqrt((adjacent * adjacent) +
(opposite * opposite));
angle = Math.acos(adjacent / hypotenuse);
if (opposite > 0) {
angleXY = sphere - angle + shiftScan;
} else {
angleXY = angle + shiftScan;
}
if (lr == LEFT) {
signalSwitchLeft = (int) ((angleXY /
(sphere / parts)) % parts);
} else if(lr == RIGHT) {
signalSwitchRight = (int) ((angleXY /
(sphere / parts)) % parts);
}
notificationOfChange();
}
final protected int getSwitch(boolean lr) {
if (lr == LEFT) {
return signalSwitchLeft;
} else if(lr == RIGHT) {
return signalSwitchRight;
} else {
// exception
// because of boolean is unreachable
return 0;
}
}
final protected void setValueAlpha (int valueAlpha) {
this.valueAlpha = valueAlpha;
valAlpha = (double) valueAlpha / (double) alphaMax;
notificationOfChange();
}
final protected double getValueAlpha() {
return valAlpha;
}
final protected void setValueLoops(int valueLoops) {
this.valueLoops = valueLoops;
notificationOfChange();
}
final protected int getValueLoops() {
return valueLoops;
}
final protected void setValueDelay(int valueDelay) {
this.valueDelay = valueDelay;
notificationOfChange();
}
final protected int getValueDelay() {
return valueDelay;
}
final private void notificationOfChange() {
setChanged();
62
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
notifyObservers();
}
final protected void setStatistics (int countClicks,
int countLights) {
if (countClicks != 0) {
statisticsAverage = statisticsMax *
countLights / countClicks;
} else if (countClicks == 0) {
// Ueber RESET erreichbar
// weil setStatistics(0, 0); aufgerufen wird
// notwendig um StatisticsView (JProgressBar)
// auf 0 zurueckzusetzen
statisticsAverage = statisticsMin;
}
notificationOfChange();
}
final protected int getStatistics() {
return statisticsAverage;
}
final protected void setLights(int instrNumber,
int signalSwitch, boolean lr) {
int lightsValue;
if(lr == LEFT) {
this.signalSwitchLeft = signalSwitch;
} else if(lr == RIGHT) {
this.signalSwitchRight = signalSwitch;
} else {
// not reachable
// because of boolean is unreachable
}
InstructionSet instrSet = new InstructionSet();
ResultSeparate result = instrSet.apply
(instrNumber, signalSwitch); // deterministic
if (result.toString() == "R") { // Light, RED
lightsValue = 0;
} else if (result.toString() == "G" ) { // Light, GREEN
lightsValue = 1;
} else if (result.toString() == "D" ) { // Light, DEFAULT
// only with RESET reachable
lightsValue = 2;
} else { // Light, DEFAULT
lightsValue = 2;
}
if (lr == LEFT) {
this.signalLightsLeft = lightsValue;
} else if (lr == RIGHT) {
this.signalLightsRight = lightsValue;
} else {
// not reachable
}
notificationOfChange();
}
final protected int getLights (boolean lr) {
if(lr == LEFT) {
return signalLightsLeft;
63
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
} else if(lr == RIGHT) {
return signalLightsRight;
} else {
// exeption
// because of boolean is unreachable
return 0;
}
}
final public void run() {
InstructionSet instrSet = new InstructionSet();
Simulation sim = new Simulation(instrSet);
Result result;
alpha = getValueAlpha();
loops = getValueLoops();
stop = false;
int switchL = 0;
int switchR = 0;
countClicks = getCountClicks();
countLights = getCountLights();
for (int k = 0; (k < loops) && (!stop); k++) {
try {
Thread.sleep(delayMax - getValueDelay());
} catch (InterruptedException ie) {
ie.printStackTrace();
}
int instrNo = sim.chooseInstruction(alpha);
if (loops == loopsLimit) { // Loops == 1
switchL = getSwitch(LEFT);
switchR = getSwitch(RIGHT);
} else if (loops > loopsLimit) { // Loops > 1
switchL = sim.chooseSwitch();
switchR = sim.chooseSwitch();
} else { // Loops == null or negative
// not reachable
System.err.println("DiceModel.run(): ERROR!");
}
result = instrSet.apply(instrNo, switchL,
switchR); // deterministic
setLights(instrNo, switchL, LEFT);
setLights(instrNo, switchR, RIGHT);
countClicks++;
if (result.colorL == result.colorR) {
countLights++;
}
setStatistics(countClicks, countLights);
}
stop = false;
pd.setBStop();
}
public int getCountClicks() {
return countClicks;
}
public void setCountClicks(int countClicks) {
this.countClicks = countClicks;
notificationOfChange();
64
407
408
409
410
411
412
413
414
415 }
}
public int getCountLights() {
return countLights;
}
public void setCountLights(int countLights) {
this.countLights = countLights;
notificationOfChange();
}
InstructionSet.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
public class InstructionSet {
protected String[][] colors = {
{"R", "R", "R"}, // 1. Instruction (0)
{"R", "R", "G"}, // 2. Instruction (1)
{"R", "G", "R"}, // 3. Instruction (2)
{"R", "G", "G"}, // 4. Instruction (3)
{"G", "R", "R"}, // 5. Instruction (4)
{"G", "R", "G"}, // 6. Instruction (5)
{"G", "G", "R"}, // 7. Instruction (6)
{"G", "G", "G"}, // 8. Instruction (7)
// Default for LIGHTS, only with RESET reachable
{"D", "D", "D"} // 9. Instruction (8)
};
protected Result apply(int instrNo, int switchL, int switchR) {
return new Result(switchL, switchR, colors[instrNo][switchL],
colors[instrNo][switchR]);
}
protected ResultSeparate apply(int instrNo, int switchSeparate) {
return new ResultSeparate(switchSeparate,
colors[instrNo][switchSeparate]);
}
}
LightsView.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.util.Observable;
import java.util.Observer;
public class LightsView extends Canvas implements Observer {
private static final long serialVersionUID = -8511530608735372306L;
private DiceModel dm;
private int signal;
private boolean lr;
public LightsView(DiceModel dModel, boolean leftright) {
this.dm = dModel;
this.lr = leftright;
dm.addObserver(this);
signal = dm.startLights; // Default- Signal
}
65
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
public void paint(Graphics g) {
BufferedImage theImage = new BufferedImage(this.getWidth(),
this.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics g1 = theImage.getGraphics();
Color oldColor = g.getColor();
g1.setColor(this.getBackground());
g1.fillRect(0, 0, getWidth(), getHeight());
g1.setColor(oldColor);
switch (signal) {
case 0:
paintLight(g1, dm.ENABLED, dm.DISABLED);
break;
case 1:
paintLight(g1, dm.DISABLED, dm.ENABLED);
break;
default:
paintLight(g1, dm.DISABLED, dm.DISABLED);
}
g.drawImage(theImage, 0, 0, getWidth(), getHeight(), null);
}
private void paintLight(Graphics g, boolean red, boolean green) {
g.drawRect(dm.zX - dm.bR, dm.zY - dm.hR, 2 * dm.bR, 2 * dm.hR);
g.setColor(dm.defco);
g.fillOval(dm.rX - dm.lR, dm.rY - dm.lR, 2 * dm.lR, 2 * dm.lR);
g.setColor(dm.defco);
g.fillOval(dm.gX - dm.lR, dm.gY - dm.lR, 2 * dm.lR, 2 * dm.lR);
if (red) {
g.setColor(dm.klick);
g.fillOval(dm.rX - dm.lR, dm.rY – dm.lR, 2 * dm.lR, 2 * dm.lR);
g.setColor(dm.defco);
g.fillOval(dm.gX - dm.lR, dm.gY – dm.lR, 2 * dm.lR, 2 * dm.lR);
} if (green) {
g.setColor(dm.defco);
g.fillOval(dm.rX - dm.lR, dm.rY – dm.lR, 2 * dm.lR, 2 * dm.lR);
g.setColor(dm.klack);
g.fillOval(dm.gX - dm.lR, dm.gY – dm.lR, 2 * dm.lR, 2 * dm.lR);
}
}
public void setSignal(int sig) {
this.signal = sig;
signal = dm.getLights(lr);
repaint();
}
public void update(Graphics g){
paint(g);
}
public void update(Observable obs, Object obj) {
this.dm = (DiceModel) obs;
setSignal(signal);
}
}
66
LoopsControl.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
23
24
25
26
27
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.util.Observable;
import java.util.Observer;
public class LoopsControl implements ChangeListener, Observer {
private DiceModel dm;
private int value;
private JSlider sl;
public LoopsControl(DiceModel dModel) {
this.dm = dModel;
dm.addObserver(this);
}
public void stateChanged(ChangeEvent ce) {
sl = (JSlider) ce.getSource();
if (sl.getValueIsAdjusting()) {
value = sl.getValue();
dm.setValueLoops(value);
}
}
public void update(Observable obs, Object arg) {
this.dm = (DiceModel) obs;
if (sl != null) {
sl.setValue(dm.getValueLoops());
}
}
}
LoopsTextView.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
import javax.swing.JLabel;
import javax.swing.JPanel;
import java.text.DecimalFormat;
import java.util.Observer;
import java.util.Observable;
public class LoopsTextView extends JPanel implements Observer {
private static final long serialVersionUID = 6295443550098419757L;
private DiceModel dm;
private JLabel output;
private int text;
private DecimalFormat df = new DecimalFormat("#000000");
public LoopsTextView(DiceModel dModel) {
this.dm = dModel;
text = dm.startLoops;
dm.addObserver(this);
output = new JLabel(dm.sLoops + df.format(text));
add(output);
}
public void setTextView(int text) {
this.text = text;
text = dm.getValueLoops();
67
23
24
25
26
27
28
29
output.setText(dm.sLoops + df.format(text));
}
public void update(Observable obs, Object v) {
this.dm = (DiceModel) obs;
setTextView(text);
}
}
PlayDice.java
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Font;
import java.awt.GridLayout;
import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JSlider;
public class PlayDice extends JApplet {
// von Eclipse IDE generiert
private static final long serialVersionUID = -4543724741710966619L;
// DiceModel
private DiceModel dModel;
// Panel fuer Beschriftung
private JPanel pInscription;
// Panel fuer alle Lights, Switches und Buttons
private JPanel pLightsAndSwitches;
// Panel fuer StatisticsView und AlphaBetaControl
private JPanel pStatisticsAndAlphaBeta;
// Panel fuer Beschriftungen
private JPanel pInscriptions;
// Panel fier die Bezeichnung
private JPanel pInscriptionTerm;
// Panel fuer die Quelle
private JPanel pInscriptionSource;
// Panel fuer den Urheber
private JPanel pInscriptionDeveloper;
// Font fuer die Bezeichnung
private Font fontTerm;
// Font fuer die Quelle
private Font fontSource;
// Font fuer den Urheber
private Font fontDeveloper;
// Label fuer die Bezeichnung
private JLabel lInscriptionsTerm;
// Label fuer die Quelle
private JLabel lInscriptionsSource;
// Label fuer dden Urheber
private JLabel lInscriptionsDeveloper;
// Panel fuer alle Lights und Buttons
private JPanel pLightsAndButtons;
// Panel fuer alle Switches und Leeres Panel
68
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
private JPanel pSwitchesAndEmpty;
// Panel fuer alle Buttons
private JPanel pButtonsPanel;
// Panel fuer den START- Button- Panel
private JPanel pStartButtonPanel;
// Panel fuer den STOP- Button- Panel
private JPanel pStopButtonPanel;
// Panel fuer den RESET- Button- Panel
private JPanel pResetButtonPanel;
// Panel fuer den START-Button
private JPanel pStartButton;
// Panel fuer den STOP-Button
private JPanel pStopButton;
// Panel fuer den RESET-Button
private JPanel pResetButton;
// Panel fuer Slider LOOPS und SPEED
private JPanel pLoopsAndSpeed;
// Panel fuer Leeres Panel
private JPanel pEmptyViewLS;
// Panel fuer Leeres Panel
private JPanel pEmptyViewStABL;
// Panel fuer Leeres Panel
private JPanel pEmptyViewStABR;
// Panel fuer StatisticsView und AlphaBetaControl
private JPanel pStatisticsAlphaBeta;
// Button START
private JButton bStart;
// Button STOP
private JButton bStop;
// Button RESET
private JButton bReset;
// Slider um die Anzahl von Schleifen einzustellen
private JSlider slLoops;
// Slider um die Ausfuehrgeschwindigkeit zu regeln
private JSlider slDelay;
// Slider fuer AlphaControl
private JSlider slAlpha;
// ProgressBar fuer StatisticsView
private JProgressBar pbStatistics;
// LightsView Links
private LightsView lightsViewLeft;
// LightsView Rechts
private LightsView lightsViewRight;
// ButtonControl, START
private ButtonControl startControl;
// ButtonControl, STOP
private ButtonControl stopControl;
// ButtonContral, RESET
private ButtonControl resetControl;
// SwitchView Links
private SwitchView switchViewLeft;
// SwitchView Rechts
private SwitchView switchViewRight;
// Statistics- View
private StatisticsView statisticsView;
69
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
// ALPHA- Text- View
private AlphaTextView alphaTextView;
// LOOPS- Text- View
private LoopsTextView loopsTextView;
// SPEED- Text- View
private DelayTextView delayTextView;
// LOOPS
private LoopsControl loopsControl;
// DELAY
private DelayControl delayControl;
// ALPHA
private AlphaControl alphaControl;
// SwitchControl, LEFT
private SwitchControl switchControlLeft;
// SwitchControl, RIGHT
private SwitchControl switchControlRight;
// Initialize Applet
public void init() {
dModel = new DiceModel(this);
pInscription = new JPanel();
pLightsAndSwitches = new JPanel();
pStatisticsAndAlphaBeta = new JPanel();
pInscriptions = new JPanel();
pInscriptionTerm = new JPanel();
pInscriptionSource = new JPanel();
pInscriptionDeveloper = new JPanel();
fontTerm = new Font(dModel.fontFont, Font.BOLD,
dModel.fontBig);
fontSource = new Font(dModel.fontFont, Font.BOLD,
dModel.fontMiddle);
fontDeveloper = new Font(dModel.fontFont, Font.BOLD,
dModel.fontSmall);
lInscriptionsTerm = new JLabel(dModel.inscriptionTerm);
lInscriptionsTerm.setFont(fontTerm);
lInscriptionsSource = new JLabel(dModel.inscriptionSource);
lInscriptionsSource.setFont(fontSource);
lInscriptionsDeveloper = new JLabel(dModel.inscriptionDeveloper);
lInscriptionsDeveloper.setFont(fontDeveloper);
pLightsAndButtons = new JPanel();
pSwitchesAndEmpty = new JPanel();
pStatisticsAlphaBeta = new JPanel();
pButtonsPanel = new JPanel();
pStartButtonPanel = new JPanel();
pStopButtonPanel = new JPanel();
pResetButtonPanel = new JPanel();
pStartButton = new JPanel();
pStopButton = new JPanel();
pResetButton = new JPanel();
pLoopsAndSpeed = new JPanel();
pEmptyViewLS = new JPanel();
pEmptyViewStABL = new JPanel();
pEmptyViewStABR = new JPanel();
bStart = new JButton(dModel.stringStart);
bStart.setPreferredSize(dModel.getPreferredSize());
bStart.setActionCommand(dModel.commandStart);
70
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
bStart.setEnabled(dModel.ENABLED);
bStart.setToolTipText(dModel.sToolTipStart);
bStop = new JButton(dModel.stringStop);
bStop.setPreferredSize(dModel.getPreferredSize());
bStop.setActionCommand(dModel.commandStop);
bStop.setEnabled(dModel.DISABLED);
bStop.setToolTipText(dModel.sToolTipStop);
bReset = new JButton(dModel.stringReset);
bReset.setPreferredSize(dModel.getPreferredSize());
bReset.setActionCommand(dModel.commandReset);
bReset.setEnabled(dModel.ENABLED);
bReset.setToolTipText(dModel.sToolTipReset);
slLoops = new JSlider(JSlider.HORIZONTAL, dModel.loopsMin,
dModel.loopsMax, dModel.startLoops);
slLoops.setToolTipText(dModel.sToolTipLoops);
slDelay = new JSlider(JSlider.HORIZONTAL, dModel.delayMin,
dModel.delayMax, dModel.startDelay);
slDelay.setToolTipText(dModel.sToolTipDelay);
pbStatistics = new JProgressBar();
pbStatistics.setStringPainted(dModel.ENABLED);
pbStatistics.setToolTipText(dModel.sToolTipStatistcs);
slAlpha = new JSlider(JSlider.HORIZONTAL, dModel.alphaMin,
dModel.alphaMax, dModel.startAlpha);
slAlpha.setToolTipText(dModel.sToolTipAlpha);
lightsViewLeft = new LightsView(dModel, dModel.LEFT);
lightsViewRight = new LightsView(dModel, dModel.RIGHT);
startControl = new ButtonControl(dModel);
stopControl = new ButtonControl(dModel);
resetControl = new ButtonControl(dModel);
switchViewLeft = new SwitchView(dModel, dModel.LEFT);
switchViewRight = new SwitchView(dModel, dModel.RIGHT);
statisticsView = new StatisticsView(pbStatistics, dModel);
alphaTextView = new AlphaTextView(dModel);
loopsTextView = new LoopsTextView(dModel);
delayTextView = new DelayTextView(dModel);
alphaControl = new AlphaControl(dModel);
loopsControl = new LoopsControl(dModel);
delayControl = new DelayControl(dModel);
Container cp = getContentPane();
cp.setLayout(new BorderLayout());
cp.add(BorderLayout.NORTH, pInscription);
cp.add(BorderLayout.CENTER, pLightsAndSwitches);
cp.add(BorderLayout.SOUTH, pStatisticsAndAlphaBeta);
pInscription.add(pInscriptions);
pInscriptions.setLayout(new GridLayout(3, 1));
pInscriptions.add(pInscriptionTerm);
pInscriptionTerm.add(lInscriptionsTerm);
pInscriptions.add(pInscriptionSource);
pInscriptionSource.add(lInscriptionsSource);
pInscriptions.add(pInscriptionDeveloper);
pInscriptionDeveloper.add(lInscriptionsDeveloper);
pLightsAndSwitches.setLayout(new GridLayout(2, 1));
pLightsAndSwitches.add(pLightsAndButtons);
pLightsAndSwitches.add(pSwitchesAndEmpty);
pLightsAndButtons.setLayout(new GridLayout(1, 3));
71
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
pLightsAndButtons.add(lightsViewLeft); // LightsView, LEFT
pLightsAndButtons.add(pButtonsPanel);
pLightsAndButtons.add(lightsViewRight); // LightsView, RIGHT
pButtonsPanel.setLayout(new GridLayout(3, 1));
pButtonsPanel.add(pStartButtonPanel);
pStartButtonPanel.setLayout(new BorderLayout());
pStartButtonPanel.add(BorderLayout.SOUTH, pStartButton);
pStartButton.add(bStart);
pButtonsPanel.add(pStopButtonPanel);
pStopButtonPanel.setLayout(new BorderLayout());
pStopButtonPanel.add(BorderLayout.SOUTH, pStopButton);
pStopButton.add(bStop);
pButtonsPanel.add(pResetButtonPanel);
pResetButtonPanel.setLayout(new BorderLayout());
pResetButtonPanel.add(BorderLayout.NORTH, pResetButton);
pResetButton.add(bReset);
pSwitchesAndEmpty.setLayout(new GridLayout(1, 3));
pSwitchesAndEmpty.add(switchViewLeft);
pSwitchesAndEmpty.add(pLoopsAndSpeed);
pSwitchesAndEmpty.add(switchViewRight);
pLoopsAndSpeed.setLayout(new GridLayout(7, 1));
pLoopsAndSpeed.add(loopsTextView);
pLoopsAndSpeed.add(slLoops);
pLoopsAndSpeed.add(pEmptyViewLS);
pLoopsAndSpeed.add(delayTextView);
pLoopsAndSpeed.add(slDelay);
pLoopsAndSpeed.add(pEmptyViewLS);
pLoopsAndSpeed.add(pEmptyViewLS);
pStatisticsAndAlphaBeta.setLayout(new GridLayout(1, 3));
pStatisticsAndAlphaBeta.add(pEmptyViewStABL);
pStatisticsAndAlphaBeta.add(pStatisticsAlphaBeta);
pStatisticsAlphaBeta.setLayout(new GridLayout(3, 1));
pStatisticsAlphaBeta.add(statisticsView);
pStatisticsAlphaBeta.add(alphaTextView);
pStatisticsAlphaBeta.add(slAlpha);
pStatisticsAndAlphaBeta.add(pEmptyViewStABR);
bStart.addActionListener(startControl);
bStop.addActionListener(stopControl);
bReset.addActionListener(resetControl);
switchControlLeft = new SwitchControl(switchViewLeft,
dModel, dModel.LEFT);
// switchViewLeft.addMouseMotionListener(switchControlLeft);
switchViewLeft.addMouseListener(switchControlLeft);
switchControlRight = new SwitchControl(switchViewRight,
dModel, dModel.RIGHT);
// switchViewRight.addMouseMotionListener(switchControlRight);
switchViewRight.addMouseListener(switchControlRight);
slLoops.addChangeListener(loopsControl);
slDelay.addChangeListener(delayControl);
slAlpha.addChangeListener(alphaControl);
}
public JButton getBStart() {
return bStart;
}
public void setBStart() {
72
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294 }
if (dModel.getValueLoops() == dModel.loopsLimit) {
bStart.setEnabled(dModel.ENABLED);
bStop.setEnabled(dModel.DISABLED);
bReset.setEnabled(dModel.ENABLED);
} else if (dModel.getValueLoops() > dModel.loopsLimit) {
bStart.setEnabled(dModel.DISABLED);
bStop.setEnabled(dModel.ENABLED);
bReset.setEnabled(dModel.DISABLED);
slLoops.setEnabled(dModel.DISABLED);
}
}
public JButton getBStop() {
return bStop;
}
public void setBStop() {
bStart.setEnabled(dModel.ENABLED);
bStop.setEnabled(dModel.DISABLED);
bReset.setEnabled(dModel.ENABLED);
slLoops.setEnabled(dModel.ENABLED);
}
public JButton getBReset() {
return bReset;
}
public void setBReset() {
bStart.setEnabled(dModel.ENABLED);
bStop.setEnabled(dModel.DISABLED);
bReset.setEnabled(dModel.ENABLED);
}
Result.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
public class Result {
private int switchL; // position of Switch LEFT
private int switchR; // position of Switch RIGHT
protected String colorL; // Color LEFT
protected String colorR; // Color RIGHT
protected Result(int switchL, int switchR,
String colorL, String colorR) {
this.switchL = switchL;
this.switchR = switchR;
this.colorL = colorL;
this.colorR = colorR;
}
public String toString() {
return switchL + " " + switchR + " " + colorL + " " + colorR;
}
}
ResultSeparate.java
01
02
03
04
public class ResultSeparate {
protected int switchSeparate;
private String colorSeparate;
protected ResultSeparate(int switchSeparate, String colorSeparate) {
73
05
06
07
08
09
10
11
this.switchSeparate = switchSeparate;
this.colorSeparate = colorSeparate;
}
public String toString() {
return colorSeparate;
}
}
Simulation.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import java.util.Random;
public class Simulation {
private Random rdSwitchPs = new Random();
private Random rdInstrSet = new Random();
private int nbOfInstr; // should be attribute of InstructionSet
private int nbOfSwPos;
protected InstructionSet instrSet;
protected Simulation(InstructionSet instrSet) {
this.instrSet = instrSet;
this.nbOfInstr = instrSet.colors.length - 1; // = 8
this.nbOfSwPos = instrSet.colors[0].length; // = 3
}
protected int chooseInstruction(double alpha) {
// Precondition: 0 < alpha < 1
double p = rdInstrSet.nextDouble();
double val;
double beta = 1 - alpha;
if (0 <= p && p < beta / 2) {
val = 2 * p / beta;
} else if (beta / 2 <= p && p < 1 - beta / 2) {
val = 6 * (p - 0.5) / alpha + 4;
} else {
val = 2 * (p - 1) / beta + 8;
}
if (val >= nbOfInstr) {
// not reachable
System.err.println("Simulation.chooseInstruction(): ERROR!");
}
return (int) Math.floor(val);
}
protected int chooseSwitch() {
double p = rdSwitchPs.nextDouble();
return (int) Math.floor(p * nbOfSwPos);
}
}
StatisticsView.java
01
02
03
04
05
06
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import java.util.Observer;
import java.util.Observable;
public class StatisticsView extends JPanel implements Observer {
74
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
private static final long serialVersionUID = 4410445127875722664L;
private DiceModel dm;
private JProgressBar stat;
private int value;
public StatisticsView(JProgressBar jpbS, DiceModel dModel) {
this.dm = dModel;
this.stat = jpbS;
dm.addObserver(this);
value = dm.getStatistics();
stat.setMinimum(dm.statisticsMin);
stat.setMaximum(dm.statisticsMax);
this.add(stat);
}
public void setStat(int val) {
this.value = val;
value = dm.getStatistics();
stat.setValue(value);
}
public void update(Observable obs, Object obj) {
this.dm = (DiceModel) obs;
setStat(value);
}
}
SwitchControl.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import java.awt.event.MouseEvent;
// import java.awt.event.MouseAdapter;
import java.awt.event.MouseAdapter;
// public class SwitchControl extends MouseMotionAdapter {
public class SwitchControl extends MouseAdapter {
private DiceModel dm;
private SwitchView sv;
private boolean lr;
// public SwitchControl(SwitchView sView,
// DiceModel dModel, boolean leftright) {
public SwitchControl(SwitchView sView,
DiceModel dModel, boolean leftright) {
this.sv = sView;
this.dm = dModel;
this.lr = leftright;
}
// public void mouseMoved(MouseEvent me) {
public void mouseClicked(MouseEvent me) {
if ((sv.contains(me.getX(), me.getY())) &&
(dm.circle.contains(me.getX(), me.getY()))) {
dm.setSwitch(me.getX(), me.getY(), lr);
}
}
}
75
SwitchView.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import javax.swing.JPanel;
import java.awt.Graphics;
import java.util.Observer;
import java.util.Observable;
public class SwitchView extends JPanel implements Observer {
private static final long serialVersionUID = -7140745252271819121L;
private DiceModel dm;
private int signal;
private double signalAngle;
private boolean lr;
public SwitchView(DiceModel dModel, boolean leftright) {
this.dm = dModel;
this.lr = leftright;
dm.addObserver(this);
signal = dm.startSwitch; // Default- Signal
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawOval(dm.zX - dm.rR, dm.zY - dm.rR, 2 * dm.rR, 2 * dm.rR);
g.drawString(dm.stringOne, dm.intXforOne, dm.intYforOne);
g.drawString(dm.stringTwo, dm.intXforTwo, dm.intYforTwo);
g.drawString(dm.stringTree, dm.intXforTree, dm.intYforTree);
signalAngle = (2 * Math.PI * signal / 3) - (Math.PI / 2);
g.drawLine(dm.zX, dm.zY, dm.zX + (int) ((dm.rR - 5) *
Math.cos(signalAngle)), dm.zY + (int) ((dm.rR - 5) *
Math.sin(signalAngle)));
g.dispose();
}
public void setSignal(int sig) {
this.signal = sig;
if (lr) {
signal = dm.getSwitch(dm.LEFT);
} else {
signal = dm.getSwitch(dm.RIGHT);
}
repaint();
}
public void update(Observable obs, Object obj) {
this.dm = (DiceModel) obs;
setSignal(signal);
}
}
76
UML-Diagramm
Abbildung 23:
UML-Diagramm
der Anwendung
Quelle:
eigene Darstellung
77
Herunterladen