GUI und Backend gescheit kombinieren

Status
Nicht offen für weitere Antworten.

Rock Lobster

Bekanntes Mitglied
Servus,

momentan stehe ich vor einem größeren Design-Problem. Ich hatte ja neulich auch schonmal einen Thread über meine Listener-Problematik eröffnet, aber da ist glaub nicht so ganz rübergekommen, worum es eigentlich geht. Daher versuche ich nochmal, zu beschreiben, worüber ich mir momentan den Kopf zerbreche und hoffe auf ein paar gute Vorschläge und Ideen.

Ich habe bisher hauptsächlich Spiele programmiert, und da ist der interne Programm-Ablauf nicht direkt vergleichbar mit "normalen" GUI-Anwendungen. Hier wird erstmal alles berechnet und zum Schluß gezeichnet, und das 60x in der Sekunde. Auf jeden Berechnungsschritt / Update-Vorgang erfolgt immer ein völlig neues Bild, und das Spiel darf sich auch herausnehmen, die CPU voll zu belasten.

Nun programmiere ich in unserer Firma gerade einen visuellen Audio-Player mit einigen Editor-Funktionen, und da läuft die Sache natürlich etwas anders ab. Mein Hauptproblem ist das Event-Handling.

Im Moment habe ich verschiedene Listener, je nach Aufgabe bzw. je nach Hauptklasse, und es gibt einige Klassen, die sich dort registrieren. Allerdings ist das manchmal schon sehr kompliziert, weil Listener über mehrere Klassen hinweg "weitergegeben" werden müssen, z.B. weil eine bestimmte Klasse den eigentlichen Player gar nicht kennt oder so. Und das wird dann sehr schnell ungemütlich, weil auf einmal Code in den Klassen steht, der dort eigentlich gar keine richtige Funktion hat und logisch gesehen da auch gar nicht hingehört.

Richtig schlimm ist es geworden, als die GUI kam. Diese war für mich zunächst nur ein Aufsatz auf die Backend-Logik, allerdings wird auch hier stark hin- und herkommuniziert. Ein gutes Beispiel: Man ändert per Mausklick die aktuelle Position im Audio-Sample, wodurch die GUI dann natürlich den Player benachrichtigt, welcher die Position entsprechend ändert. Auf der anderen Seite muß sich aber wiederum die GUI ändern, wenn der Player z.B. von allein die Position ändert (im einfachsten Fall passiert das z.B. dann, wenn das Stück abgespielt wird). Das heißt, es gibt viele Wechselbeziehungen, wo zwar einerseits eine Aktion in der GUI das Backend informieren muß, und andererseits passieren auch im Backend einige Dinge, die dann wieder der GUI bescheid sagen müssen. Hierbei muß man dann auch aufpassen, daß keine Zyklen entstehen, welche zum Deadlock führen können (was ich im Moment löse, indem ich immer den "Auftraggeber" mitschicke).
Die Position ist deshalb auch noch ein gutes Beispiel, weil sie sich beim Abspielen tatsächlich ständig ändert. In dem Fall erscheint es mir wieder unnötig, jedesmal der GUI bescheid zu sagen, daher hat die GUI einen Thread, der alle 50 ms nachfragt, wo die Position gerade ist. Aber auch das ist wieder recht unsauber.

Gibt es für diese Problematik saubere Lösungen? Speziell diese Wechselbeziehungen und die Zyklen sind schlimm, aber auch das Weiterreichen der Listener. Da bei mir die Hauptlogik eher "fest verdrahtet" ist, aber immer wieder erweitert wird, habe ich bereits über ein zentrales Signalsystem nachgedacht, wo sich jede Klasse für bestimmte Ereignisse registrieren kann, allerdings immer bei einer zentralen "Postdienststelle", um es mal so auszudrücken. Das könnte einiges vereinfachen, aber vielleicht kennt hier jemand auch Gründe, die gegen solch ein System sprechen. Falls es dennoch eine gute Wahl sein könnte, ist die nächste Frage, wie man diese zentrale Stelle implementiert - eigentlich möchte ich möglichst auf Singletons verzichten.
 

SilentJ

Bekanntes Mitglied
Für die GUI und die eigentliche Abspiellogik würde sich das Observer-Pattern eignen. Die GUI wird von der Abspiellogik per notify() darüber informiert, dass eine neue Darstellung der Position notwendig wird.

Das ist zumindest ein Tipp für einen Teil deines Problems. Das ganze Problem löst er freilich nicht.
 

Rock Lobster

Bekanntes Mitglied
Vielen Dank für den Tip, allerdings habe ich das Gefühl, daß das Observer-Pattern nichts wesentlich anderes ist als der Einsatz von Listenern. Kann das sein? Ich habe mir gerade auch nochmal den Wikipedia-Artikel geöffnet, irgendwie läuft da im Grunde doch das gleiche ab. Oder was ist der "würzige" Unterschied zwischen Listenern und Observern?
 

SilentJ

Bekanntes Mitglied
Das Observer-Pattern ist eine Obermenge, zu der in Java auch die Listener gehören. Das Observer-Pattern als solches bietet aber die Möglichkeit, "smarte" oder maßgescheiderte Events auszulösen bzw. zusätzliche Logik in das den Event kapselnde Objekt einzubauen. Normale Listener in Java sind nicht wirklich schwergewichtig in diesem Sinne.
 

Rock Lobster

Bekanntes Mitglied
Verstehe ich leider immer noch nicht - gibt es ein Beispiel, das den Unterschied zeigen würde, im Vergleich zum Einsatz von Listenern?

Um nochmal auf das Problem mit der zentralen Signal-Klasse zurückzukommen: Ich fände es momentan am praktischsten, wenn jedes Objekt, das in der Lage ist, Nachrichten zu verschicken, sich an eine einzige Stelle wendet, dort die Nachricht "abgibt", und diese wird dann an alle diejenigen Objekte verschickt, die sich für dieses Ereignis ebenfalls an dieser zentralen Stelle registriert haben.
Das Problem ist nun, daß ich dazu einen Singleton bräuchte, um von jeder erdenklichen Stelle im Code darauf zuzugreifen, sei es, um eine Nachricht zu verschicken, oder um einen Empfänger zu registrieren. Eigentlich würde das ja perfekt funktionieren, aber ich will keinen Singleton, weil ich somit nicht mehr die Möglichkeit habe, in eine Applikation ZWEI Player einzubauen. Diese würden sich ja dann die zentrale Stelle teilen, und die Nachrichten, die verschickt würden, würden zum Teil auch an die Objekte aus dem anderen Player verschickt.

Die einzige Lösung, die mir einfällt, wäre den Player als "Wurzel" zu verwenden, und diesem Player solch einen Nachrichtendienst als Member zu geben. Allerdings habe ich dann wiederum das Problem, daß jedes Objekt, das eine Nachricht verschicken oder empfangen will, diesen Player kennen muß, und das will ich nicht.

Gibt es genau für dieses Problem eine Lösung? Ein "scoped Singleton" sozusagen. Aber wie lege ich den Scope fest?
 
Status
Nicht offen für weitere Antworten.

Ähnliche Java Themen

Neue Themen


Oben