2009-11-18 11 views
5

Sobald das Problem des Ladens von Plugins gelöst ist (in .NET durch MEF in out Fall), ist der nächste Schritt zu lösen, die Kommunikation mit ihnen. Der einfache Weg besteht darin, eine Schnittstelle zu implementieren und die Plugin-Implementierung zu verwenden, aber manchmal muss das Plugin nur die Art und Weise erweitern, wie die Anwendung funktioniert, und es kann viele Erweiterungspunkte geben.Architektur für Erweiterung/Plugin-Kommunikation

Meine Frage ist, wie man mit diesen Erweiterungspunkten umgehen. Ich habe verschiedene Möglichkeiten gesehen, dies zu tun, aber ich bin nicht sicher, ob der Vor-und Nachteile eines jeden und wenn es mehr und bessere Möglichkeiten, um dies zu erreichen:

  • Events: Hinzufügen von statischen Events zu allen Sachen wir wollen "erweiterbar" machen. Wenn ich z. B. eine benutzerdefinierte Überprüfung für eine Benutzerklasse hinzufügen möchte, kann ich einen statischen OnValidation-Ereignishandler hinzufügen und ihm Ereignisse aus dem Plug-in hinzufügen, wenn es erstellt wird.
  • Messaging: Mit einem Bus und Nachrichten. Das Plugin kann eine bestimmte Nachricht abonnieren und Dinge tun, wenn eine andere Klasse diese Nachricht veröffentlicht. Die Nachricht sollte den Kontext enthalten, in dem das Plugin funktionieren kann. Im Validierungsfall veröffentlicht die Logikschicht eine UserValidation-Nachricht und das Plug-in reagiert, wenn die Nachricht empfangen wird.
  • Schnittstellen: Die Host-Anwendung ist verantwortlich für den Aufruf aller Plugins, die bestimmte Schnittstellen implementieren und ihnen den Kontext der aktuellen Operation geben. Im Falle einer Validierung kann das Plugin einen IValidator oder IUserValidator mit einer Validate-Methode (Objektkontext) implementieren.

Haben Sie jemals einen der exponierten Ansätze verwendet? Welche hat am besten für dich funktioniert?

Und bevor Sie fragen, ist unsere Anwendung ein erweiterbarer Kern (Benutzer, Rola und Content-Management), um unsere kundenspezifischen Content-Centric-Web-Anwendungen darüber hinaus zu bauen. Alles basiert auf ASP.NET MVC.

Antwort

2

Ein Schlüssel für Ihre Designentscheidung ist es, zu analysieren und ein klares Bild davon zu bekommen, wie unterschiedlich die Plugins voneinander sein werden.

z. Bei statischen Ereignissen müssen Sie wahrscheinlich jedes Ereignis als eine Form von Token, Enum, Objekt usw. definieren. Das Definieren eines neuen Satzes von Ereignissen für jedes Plugin wirkt natürlich gegen Ihr gesamtes Design, insbesondere in Bezug auf lose Kopplung und Wiederverwendung.

Wenn Ihre Plugins sehr unterschiedlich sind, können Sie von einer Bus-/Messaging-Architektur profitieren, da Sie in diesem Fall Domänen/Kategorien des Kommunikationsaustauschs einführen können, die die Plugins abonnieren können. I.e. Eine Reihe von Ereignissen und Nachrichten kann sich in einer bestimmten Interessensdomäne befinden. Beachten Sie, dass die Kommunikation innerhalb einer bestimmten Kategorie statische Ereignisse weiterhin verwenden kann, so dass sich diese beiden Alternativen nicht gegenseitig ausschließen.

Direkte Schnittstellen von den Plugins implementiert ist meiner Erfahrung nach der strengste Ansatz der Plugin-Architektur. Das Erweitern der Plugin-Schnittstelle impliziert normalerweise eine Code-Änderung sowohl beim Plugin als auch beim Provider. Sie müssen über eine solide allgemeine Benutzeroberfläche verfügen, von der Sie wissen, dass Ihre Anwendung noch eine Weile bestehen kann.

Es kann einfacher sein, dass Sie es mit dem Entwurf zu beschäftigen, indem brechen in zwei Aspekte ab - Kommunikationskanal und Protokoll. Statische Ereignisbehandlung ist ein Protokollproblem, während Bus-Messaging und direkte Schnittstellen ein Kanalproblem darstellen.

Generell würde ich sagen, dass das Protokoll von Anfang an am schwierigsten zu entwerfen ist, da Sie kein solides Gefühl dafür haben, wie allgemein oder spezifisch Sie die Linie zeichnen können.

EDIT: Lars einen wichtigen Punkt in seinem Kommentar - wenn Ihre Plattform Ausnahmen unterstützt, können Sie eine Menge von der Fehlerbehandlung zentralisieren, wenn eine direkte Schnittstellen, entlastet die Plugins aus, die Fehler zu behandeln, die generisch sind und vielleicht Ihre spezielle Domäne (z. B. "Fehler beim Laden des Plugins" oder "Fehler beim Öffnen der Datei"). Diese Vorteile scheinen jedoch zu schwinden, wenn Sie jedes Mal, wenn Sie Plugins hinzufügen, die Schnittstellen pflegen müssen. Der schlimmste Fall ist, wenn die Schnittstellen auf dem Weg inkonsistent werden, weil Sie nicht wussten, was sie von Anfang an unterstützen sollten. Das Refactoring des gesamten Interfacedesigns, wenn eine erhebliche Anzahl von Plugins bereits konzipiert wurde, ist keine leichte Aufgabe.

+0

Schnittstellen wären wahrscheinlich mein Ansatz, obwohl es von der Anwendung abhängt und es Plugin benötigt. Aber es ist eine sehr saubere Möglichkeit, Plugins zu machen, und es wird auch einfach sein, Ausnahmen vom Plugin zu isolieren. –

0

Ich würde mit dem Observer Muster gehen. Von der GOF:

eine Abhängigkeit vieler Eins-zu-Define zwischen Objekten, so dass, wenn eine Objektänderungen angeben, alle seiner unterhalte werden benachrichtigt und automatisch aktualisiert.

Auch bekannt als Publish-Subscribe Ich würde vorschlagen, dass es Fall zwei in Ihren Beispielen am ehesten entspricht.

+0

IMHO das Beobachtermuster ist eine Ebene höher von diesem Problem. I.e. Alle Alternativen, die er präsentiert, würden in dieses Muster passen. Das vorliegende Problem hat vielmehr mit einer implementierungsspezifischen Entscheidung des Beobachtermusters zu tun. – sharkin

+0

Beim erneuten Lesen und mit weiterer Verdauung, denke ich, dass Sie wahrscheinlich R.A. – Martin