Relationen zwischen UML-Elementen
- Design der Pfeile im UML-Diagramm:
- Beziehungen zwischen UML-Objekten:
- mögliche Implementierungen
- als eigene Liste der Pfeile
- als spezielle UmlElement's
- als Teil eines vorhandenen Objekts (z.B. Teil des Ausgangsobjekts)
- passen gut in das MVC-Schema
- interne Daten in Model-Klasse Arrow
(Kind von UmlElement)
- Sender-, Empfänger-Objekt
- Art der Relation (ArrowType)
als Enumeration
- Name (über UmlElement)
- Darstellung mit ArrowView
- Linien- und Pfeiltyp abhängig vom ArrowType
nach UML
- Anfangs- und Endpunkte durch Start- und Endobjekt festgelegt
![Bezugspunkte der Pfeile](../images/bild48.png)
- Besonderheit: Pfeile werden mit Start-/Endobjekt mitverschoben
- Erweiterung: Name am Pfeil anzeigen
- verändern mit ArrowEditor
- Ändern von ArrowType
und Namen
- Pattern Observer:
- Pattern-Typ Behavioural
- Problem
- Objekt (Observable) soll seine
Änderungen an beobachtende Objekte melden
- Art und Anzahl der Beobachter unbekannt
- Lösung
- Beobachter implementieren Interface Observer
mit Methode update
- Beobachter melden sich bei Observable an
- beobachtetes Objekt hat Liste der Observer
- ruft bei Änderung deren update-Methode
auf
![UML-Diagramm für Observer](../images/bild33.png)
- Konsequenzen
- beliebige Anzahl von Observern möglich (+)
- Kopplung zwischen Observable und Observern sehr lose
(+)
- keine Information über Art der Änderung →
u.U. unnötige Update-Kaskade (-)
- Bemerkungen
- Teil des MVC-Patterns
- bei Swing: Events und Listener
- in java.util vorhanden
- Implementierung im UML-Editor:
- ArrowView ist Observer
(hat update-Methode)
- View
ist Observable
- hat Liste der Observer
- hat Methoden zum An- und Abmelden
- hat Methode zum Informieren der Observer
- Problem
- Was passiert bei mehrfachem Anmelden eines Observers?
- Unterschiede zu MVC
- Observable ist hier der View
- es geht nur ums Verschieben, nicht um das Model
- Alternative Implementierung über java.beans.PropertyChangeSupport:
- Vorteil: schon vorhanden
- Alternative java.util.Observable
ist nicht serialisierbar
- Schwierigkeit: View kann nicht
von PropertyChangeSupport erben
- Ausweg: View
hat PropertyChangeSupport-Objekt und leitet Anfragen
weiter
- Methodennamen von PropertyChangeSupport
werden dabei an Observable angepasst
- wichtiger Trick: Wen ich nicht beerben kann, den muss
ich fressen!
- Problem: statt Observer wird
PropertyChangeListener gebraucht
- entweder ArrowView anpassen
(update → propertyChange)
- oder eleganter über Adapter-Pattern
- Pattern Adapter:
- Pattern-Typ Structural
- Problem
- Interface einer vorhandenen Klasse (Adaptee)
passt nicht zu dem Interface (Target), das
eine Kundenklasse (Client) erwartet
- Lösung
- neue Adapterklasse (Adapter)
hat richtiges Interface Target
- übersetzt Aufrufe für Adaptee
![UML-Diagramm für Adapter](../images/bild51.png)
- Konsequenzen
- eigentlich inkompatible Objekte können zusammenarbeiten
(+)
- u.U. schwierig, Parameter richtig zu übertragen
(-)
- Adapter u.U. nur teilweise Ersatz für Target (-)
- konkrete Umsetzung mit ObserverAdapter
- Implementierung des Zeichnens:
- verwendet einige Funktionen aus 2D-Graphik von Swing
- zur Benutzung Standard-Graphikkontext einfach "umwidmen"
- Graphics2D g2 = (Graphics2D) g;
- gestrichelte Linien mit java.awt.BasicStroke
- Konstruktor erhält Array mit Längen von Strichen
- anwenden mit g2.setStroke(BasicStroke);
- beliebige Polygone mit Klasse java.awt.Polygon
- Konstruktor mit Punkten als Arrays für x- und
y-Koordinaten
- zeichnen mit g2.draw (Umriss)
oder g2.fill (ausgefüllt)
- prüfen, ob Punkt im Polygon liegt, mit pol.contains(Point)
- pol.invalidate() nach Änderungen
an den Koordinaten wegen Caching
- Verwaltung von GUI-Zuständen:
- verschiedene Aktionen beim Anklicken eines Objekts, je
nach vorheriger Icon-Auswahl
- normalerweise zweischrittig
- Aktion auswählen (Icons "Edit", "Delete")
- zugehöriges Objekt auswählen
- bei Pfeilen dreischrittig
- Pfeilart auswählen (horizontal/vertikal)
- Startobjekt und Zielobjekt auswählen
- Fehler (kein Objekt getroffen) → Grundzustand
- außerdem noch Verschieben von Objekten mit der Maus
- Implementierung "hemdsärmlig" mit Konstanten
und großem switch
- zugrundeliegendes Modell:
- endlicher Automat mit Zuständen aus UmlGui
- Übergänge gemäß Transitionsdiagramm
![Transitionsdiagramm](../images/bild49.png)
- Weitere Bemerkungen zur Implementierung:
- Problem mit Stroke
- Stroke wird im Konstruktor
initialisiert
- kann nicht serialisiert werden (Stroke
ist nicht Serializable)
- beim Laden nicht initialisiert (läuft nicht durch
den Konstruktor)
- Lösung: Lazy Initialisation
- Gleichheit von ArrowType-Werten
- type.equals() (von java.lang.Object
geerbt) testet nur Gleichheit der Referenz
- beim Laden entstehen neue Objekte → Adressen sind
verschieden
- daher: equals() testet auf
gleichen name-Wert
- auch hashCode() anpassen!
- das fertige Programm als Applet
(ohne Laden/Speichern)