Stellen Sie sich vor, Sie haben ein Softwaremodul, das ein Plugin für ein Programm ist (ähnlich wie Eclipse), und Sie möchten, dass es eine API hat, die andere Plugins aufrufen können. Ihr Plugin ist nicht frei verfügbar, so dass Sie eine separate API - Modul haben wollen, das ist frei verfügbar und ist das einzige , was andere Plugins müssen direkt Link zu - API - Clients nur mit dem API - Modul zusammenstellen können, und nicht das Implementierungsmodul, auf dem Erstellungspfad. Wenn die API auf kompatible Weise weiterentwickelt werden muss, können Client-Plugins das API-Modul sogar in ihre eigenen Jars aufnehmen (um zu verhindern, dass Error
s auf den Zugriff auf nicht vorhandene Klassen zurückzuführen ist).
Die Lizenzierung ist nicht der einzige Grund, API und Implementierung in separate Module zu integrieren. Es kann sein, dass das Implementierungsmodul komplex ist und unzählige eigene Abhängigkeiten aufweist. Eclipse-Plugins haben normalerweise interne und nicht interne Pakete, wobei die nicht internen Pakete einem API-Modul ähneln (beide sind im selben Modul enthalten, können jedoch getrennt werden).
Ich habe dafür verschiedene Alternativen gesehen:
Die API befindet sich in einem von der Implementierung getrennten Paket (oder einer Gruppe von Paketen). Die API-Klassen rufen direkt Implementierungsklassen auf. Die API kann ohne die Implementierung nicht aus dem Quellcode kompiliert werden (was in einigen seltenen Fällen wünschenswert ist). Es ist nicht einfach, die genauen Auswirkungen des Aufrufs von API-Methoden vorherzusagen, wenn die Implementierung nicht installiert ist. Daher vermeiden Clients dies normalerweise.
package com.pluginx.api; import com.pluginx.internal.FooFactory; public class PluginXAPI { public static Foo getFoo() { return FooFactory.getFoo(); } }
Die API befindet sich in einem separaten Paket und verwendet Reflection, um auf die Implementierungsklassen zuzugreifen. Die API kann ohne Implementierung kompiliert werden. Die Verwendung von Reflection kann zu Leistungseinbußen führen (Reflection-Objekte können jedoch zwischengespeichert werden, wenn es sich um ein Problem handelt. Es ist einfach zu steuern, was passiert, wenn die Implementierung nicht verfügbar ist.
package com.pluginx.api; public class PluginXAPI { public static Foo getFoo() { try { return (Foo)Class.forName("com.pluginx.internal.FooFactory").getMethod("getFoo").invoke(null); } catch(ReflectiveOperationException e) { return null; // or throw a RuntimeException, or add logging, or raise a fatal error in some global error handling system, etc } } }
Die API besteht nur aus Schnittstellen und abstrakten Klassen sowie einer Möglichkeit, eine Instanz einer Klasse abzurufen.
package com.pluginx.api; public abstract class PluginXAPI { public abstract Foo getFoo(); private static PluginXAPI instance; public static PluginXAPI getInstance() {return instance;} public static void setInstance(PluginXAPI newInstance) { if(instance != null) throw new IllegalStateException("instance already set"); else instance = newInstance; } }
Das gleiche wie oben, aber der Client-Code muss die ursprüngliche Referenz von einer anderen Stelle erhalten:
// API package com.pluginx.api; public interface PluginXAPI { Foo getFoo(); } // Implementation package com.pluginx.internal; public class PluginX extends Plugin implements PluginXAPI { @Override public Foo getFoo() { ... } } // Client code uses it like this PluginXAPI xapi = (PluginXAPI)PluginManager.getPlugin("com.pluginx"); Foo foo = xapi.getFoo();
Tu es nicht. Stellen Sie sicher, dass Clients direkt mit dem Plugin verknüpft sind (verhindern Sie jedoch, dass sie Nicht-API-Methoden aufrufen). Dies würde es für viele andere Plugins (und die meisten Open Source-Plugins) schwierig machen, die API dieses Plugins zu verwenden, ohne einen eigenen Wrapper zu schreiben.
Haben Sie sich die ServiceLoader- Mechanismen in Java angesehen? Grundsätzlich können Sie die Implementierung einer Schnittstelle über die Manifestdatei in einem JAR angeben. Oracle bietet auch einige weitere Informationen zu Plugins in Java-Programmen.
quelle
Soweit ich weiß, verwenden die Leute oft das Fabrikmuster dafür.
Sie fügen die API-Schnittstellen in ein separates Modul ein (z. B. eine JAR-Datei). Wenn die Clients die API verwenden möchten und Zugriff auf eine Implementierung der API haben, verfügt die Implementierung der API über einen werkseitigen Einstiegspunkt für die Clients Erstellen Sie konkrete Objekte, die diese API implementieren.
Dies bedeutet, dass Ihre erste Idee von oben die größte Ähnlichkeit aufweist.
quelle