GUI
GElement
GElement
...
GElement
Wir kommen vermutlich gar nicht drumrum, jedes Diagrammelement
einmal im GUI und einmal im Modell abzubilden: die GUI braucht
Objekte die sich zeichnen und auf Events reagieren können; ein
abgekoppeltes Modell ist aber sinvoll, damit ein entferner Client
darauf genauso zugreifen kann wie die lokale GUI.
observes
observes
observes
observes
Es gibt also zwei Objektarten, ich habe sie mal GElement und
MElement genannt, wobei sämtliche Daten im MElement liegen, das
GElement enthält nur GUI-Logik. Jedes GElement observiert sein
MElement, um von Änderungen zu erfahren; das GUI observiert das
Modell als ganzes, um über Ereignisse wie das Erzeugen neuer
Elemente informiert zu werden.
Es entstehen also zwei korrespondierende Objektgraphen.
Fehlt also nur noch die Kopplung mit einem zweiten Prozess.
Modell
MElement
MElement
...
MElement
Server
Client
GUI
GUI
GElement
...
GElement
GElement
GElement
GElement
se
rv
es
obs
...
MElement
observes
ob
observes
ob
se
ob
rv
es
se
rve
s
MElement
observes
Modell
...
ServerProxy
s
observes
rve
se
ob
s
rve
se
ob
ob
es
serv
es
obs
erv
observes
observes
observes
observes
ClientProxy
GElement
erv
es
Modell
MElement
...
MElement
MElement
MElement
Das könnte dann so aussehen (ich benutze hier Proxy im Sinne von Stellvertreter – der ClientProxy vertritt den Client gegenüber dem Modell
im Server). Anders als in meiner Tafelskizze braucht das Modell nicht zu wissen ob es im Client oder Server ist, da sich die Proxies als
Observer anmelden, genau wie die GUI. Die MElemente verhalten sich auch in beiden Fällen gleich, bis auf einen Unterschied, das Locking –
MElemente im Server machen das selbst, während MElemente des Clients dazu das entsprechende MElement im Server befragen müssen.
Es wäre aber ungeschickt, jede MElement-Klasse in zwei Ausprägungen zu implementieren …
Server
Client
GUI
GUI
GElement
...
GElement
GElement
GElement
GElement
se
rv
es
obs
observes
ob
observes
observes
ob
se
ob
rv
es
se
rve
s
Modell
...
ServerProxy
s
observes
rve
se
ob
s
rve
se
ob
ob
es
serv
es
obs
erv
observes
observes
observes
observes
ClientProxy
GElement
erv
es
Modell
MElement
MElement
...
MElement
MElement
MElement
...
MElement
MasterLock
MasterLock
...
MasterLock
SlaveLock
SlaveLock
...
SlaveLock
… besser geht es per Strategy Pattern: MElemente machen das Locking gar nicht selbst, sondern bekommen ein Lock-Objekt, das es dann
als MasterLock oder SlaveLock gibt. SlaveLocks fragen über den ServerProxy beim jeweiligen MasterLock an. Was im MasterLock drinsteckt
weiß ich noch nicht, das könnte ein java.util.concurrent.locks.Lock sein oder vielleicht auch eine java.util.concurrent.Semaphore, je nachdem
wie die Arbeitsteilung zwischen den Threads im Server aussieht. In jedem Fall ist es vermutlich gut, zusätzlich zu speichern wer das Lock hält,
und diese Information (zusammen mit dem Lockstatus) den SlaveLocks mitzuteilen; dann kann man in der GUI kenntlich machen, welche
Objekte gerade von wem bearbeitet werden, außerdem kann ein SlaveLock, das weiß dass das Lock vergeben ist, Locking-Anfragen sofort
ablehnen ohne das MasterLock befragen zu müssen.
Und nachdem ich die ganzen schönen Bildchen gemalt habe fällt mir auf, dass man die Trennung in GElement und MElement wahrscheinlich
doch nicht braucht. Mist. Es gibt gute Argumente gegen die Trennung: Eine Trennung von Inhalt und Darstellung kann es bei dieser
Anwendung eigentlich gar nicht geben, denn bei einem Diagramm ist die Darstellung der Inhalt; und es könnte Situationen geben, in denen
das Modell das konkrete Aussehen eines Elements sehr genau kennen muss – z.B. wenn eine Kante wissen möchte, wo sie sich an einen
Knoten anheften kann. Damit bleibt wohl als einziger Vorteil der Trennung die erhöhte Komplexität.