Best Practice MVC mit Plugin-Feature

Hallo,
ich verwende für eine Applikation das MVC Pattern und Frage mich, was der beste Weg ist Plugins zu integrieren.

Ein Plugin soll die Möglichkeit haben die GUI zu modifizieren, wie z.B. MenuItems dem Menu hinzufügen und andere optischen wie funktionalen Veränderungen vornehmen können.
Ein Plugin soll die Möglichkeit haben dem Model etwas hinzufügen ( etwas 'löschen' ist nicht vorgesehen )
Ein Plugin soll auf die hinzugefügte Funktionalität reagieren können.

Ich habe mir ein kleines Beispiel ausgedacht.

Angenommen meine View besteht nur aus einem Textfeld und einem 'save' Button. Mein Model aus einem String und der Kontroller kann als einziges diesen String serialisieren und speichern.

Wie baue ich jetzt am besten einen PluginLoader, der in der Lage ist der View einen zweiten Button hinzuzufügen ( saveAsJSON ) und dem Controller die Funktionalität erweitern kann.

Mein Ansatz wäre jetzt wie folgt:

1. Dem Controller wird eine Map hinzugefügt, die zwischen einem Key und einem PluginExecuteObjekt mappt.
2. Dem Controller wird eine Methode pluginExecuteCommand(String key) hinzugefügt, die auf die Map Zugriff hat und das zum Key passende Objekt heraussucht und eine execute(Model model) Methode aufruft.
3. Vor dem Aufbau der GUI wird das Plugin geladen ( eventuell via Reflection ).
4. Beim Aufbau werden dem Plugin Teile der GUI übergeben, sodass das Plugin der GUI Element hinzufügen kann mit einem Listener zur Methode pluginExecuteCommand("my-json-save-plugin")
5. Das Plugin fügt der Map des Controllers den Key "my-json-save-plugin" hinzu und ein vom Plugin bereitgestelltes pluginExecuteCommand.

(6.) Der User drückt auf den saveAsJSON-Button, die Methode pluginExecuteCommand wird mit dem String "my-json-save-plugin" aufgerufen. Der Controller führt die execute() Methode des PluginObjektes aus und übergibt ihr das Model. Die Plugin Implementation entimmt dem Model den String und speichert dieses als json-Datei ab.


Ich finde das Konzept etwas amateurhaft, aber egal wie ich mich den Kopf zerbreche ich finde keine bessere Lösung. Wie stellt ihr euch eine solches Plugin vor ? Trifft diese Implementierung das was Ihr euch darunter Vorstellt oder muss es noch verbessert werden ? Wenn ja wo ?

Falls Ihr das Beispiel als Code haben wollt, kann ich es gerne Posten, nur dachte ich mir vielleicht bei den relativ vielen Klassen, dass es als Bergbeschreibung vielleicht etwas übersichtlicher ist.
 
Du könntest z.B. jedem Plugin die Möglichkeit geben, bestimmte eigene Elemente hinzuzufügen, z.B. ein TabPane. Jedes PlugIn könnte ein TabPane mit seine GUI-Elementen übergeben, gleiches für MenuItems, ContextMenuItems, usw.

Dann würde ich einem Plugin die Möglichkeit geben, sich als Listener für eine Auswahl bestimmter Modelereignisse zu registrieren. (Nicht alles muß über alle Veränderungen benachrichtigt werden.)

Und wenn du eine Commandstruktur hast, dann kannst du jedem Plugin die Möglichkeit geben, die requestCommand(Command c)-Methode des Controllers zu triggern.
 
Du könntest z.B. jedem Plugin die Möglichkeit geben, bestimmte eigene Elemente hinzuzufügen, z.B. ein TabPane. Jedes PlugIn könnte ein TabPane mit seine GUI-Elementen übergeben, gleiches für MenuItems, ContextMenuItems, usw.
Der Ansatz ist viel besser, so kann das Plugin, die vorhandenen Element nicht in irgendeiner Art und Weise überschreiben.

Dann würde ich einem Plugin die Möglichkeit geben, sich als Listener für eine Auswahl bestimmter Modelereignisse zu registrieren. (Nicht alles muß über alle Veränderungen benachrichtigt werden.)
Das stimmt, also wäre im übertragendem Sinne jedes Plugin ein Mini-Controller wenn ich das richtig, verstehe.
Hättest du auch noch eine gescheite Idee, wie ich ich das Model ggf. vom Plugin aus erweitern könnte ?

Leider nicht, ich denke du meinst das Command Pattern ? Allerdings muss ich gestehen, kenne ich in diesem keine RequestCommand methode oder reden wir da aneinander vorbei ?
 
Für so etwas habe ich mal die NetBeans Platform (damals noch die 6er) verwendet, die bietet all das out of the box: ein Modulsystem, wobei jedes Modul die Umgebung (z. B. Menüs) verändern kann (insbesondere deklarativ), außerdem lose Kopplung über Interfaces und Lookups. Schöne Sache, allerdings braucht es einige Zeit, bis man durchsteigt und die Anwendungen sind nicht gerade leichtgewichtig...

Wenn Du das selbst machen willst, würde ich ein Plugin erstmal ganz abstrakt betrachten: ein Plugin ist die Implementierung einer seitens der Anwendung vorgegebenen Schnittstelle. Beispielsweise ist die JDBC-API eine Sammlung von Interfaces, der konkrete JDBC-Treiber - die Implementierung - ist das Plugin.

Jetzt ist die Frage, welche Anforderungen die Anwendung an das Plugin hat. Bei JDBC sind diese recht konkret. Ganz abstrakt würde ein Runnable-Interface reichen. Damit ließen sich bereits Plugins realisieren. Allerdings wird Dir das nicht reichen.

Du könntest Dir überlegen, dass ein Plugin einen Lebenszyklus hat, also zumindest seitens der Anwendung "gestartet" (initialisiert) wird. Dabei könnten Kontext-Informationen übergeben werden, damit das Plugin weiß, "worin" es läuft.

Dann ist die Frage, wie Anwendung und Plugin weiter miteinander kommunizieren sollen. So könnte z. B. die Anwendung vom Plugin Informationen abfragen, um ein Menü zu gestalten. Man kann den Spieß aber auch umdrehen und dem Plugin die Gestaltung überlassen, indem man ihm Zugriff auf das "Menüsystem" ermöglicht. Im Ergebnis erhältst Du letztlich das, was @White_Fox beschrieben hat.

Wenn Du das Model per Plugin erweitern können willst, muss das Model ebenso darauf ausgelegt sein. D. h. Schnittstellen und Implementierungen dazu. Auch hier musst Du Dir wieder überlegen, wie die Kommunikation ablaufen soll.
 
Leider nicht, ich denke du meinst das Command Pattern ? Allerdings muss ich gestehen, kenne ich in diesem keine RequestCommand methode oder reden wir da aneinander vorbei ?
Wahrscheinlich. Ich schreibe gerade ein Programm, da funktioniert das mit den Commands wie folgt:
-View erstellt ein Command-Objekt und parametrisiert es (die Command-Objekte kommen aus einer Factory, das Model implementiert ein passendes Commandable-Interface das weitreichende Datenzgriffe erlaubt, dank der Factory bekommt die View diesen Zugriff jedoch nicht).
-View übergibt dem Controller das Command-Objekt über die requestCommand-Methode. Der Controller führt das Command-Objekt aus, jedes Commandobjekt stellt eine execute()-Methode zur Verfügung, die getriggert wird. Das soll später teilweise auch mehrfach geschehen (Rückgängig-Wiederholen-Funktion).

Ein Teil von deinem Problem hab ich irgendwie auch gelöst, ich habe verschiedene Teile der View als eigenständige Klassen ausgeführt. Ich habe da z.B. eine Tabelle, die auch ein Kontextmenü enthält. Beides, Tabelle und Kontextmenü, sind als eigenständige Klassen gebaut. Bei mir war der Hauptgrund dafür aber, daß mir knapp 1.000 Codezeilen einfach zu unübersichtlich waren. Und dabei ist das noch lange, lange nicht fertig und längst nicht alles drin, was da noch rein soll.
Aber eine Erweiterung könnte man so ohne weiteres ebenso unterbingen.

Ich habe das Commandpattern noch nie vorher verwendet, um ehrlich zu sein ist das auch mein erstes ernsthaftes Programm daß ich überhaupt schreibe. (Umso mehr staune ich, was man dabei so alles lernt.)
 
Passende Stellenanzeigen aus deiner Region:

Neue Themen

Oben