あるプログラムへのプラグイン(Eclipseに類似)であるソフトウェアモジュールがあり、他のプラグインが呼び出すことができるAPIが欲しいと想像してください。あなたが別のAPIモジュール、持っていると思いますので、あなたのプラグインは、自由に利用できないではなく、実装モジュールAPIクライアントのみAPIモジュールをコンパイルすることができ、 -自由に利用でき、他のプラグインが直接へのリンクはする必要が唯一のものですがビルドパス上。APIが互換性のある方法で進化するように制限されている場合、クライアントプラグインはAPIモジュールを独自のjarに含めることもできます(Error
存在しないクラスがアクセスされることによるsの可能性を防ぐため)。
ライセンスは、APIと実装を別々のモジュールに配置する唯一の理由ではありません。実装モジュールが複雑で、独自の無数の依存関係がある可能性があります。Eclipseプラグインには通常、内部パッケージと非内部パッケージがあり、非内部パッケージはAPIモジュールに似ています(どちらも同じモジュールに含まれていますが、分離することができます)。
私はこれのいくつかの異なる選択肢を見てきました:
APIは、実装とは別のパッケージ(またはパッケージのグループ)にあります。APIクラスは、実装クラスを直接呼び出します。API は、実装なしでソースからコンパイルすることはできません(まれなケースでは望ましいことです)。実装がインストールされていない場合、APIメソッドの呼び出しの正確な影響を予測することは簡単ではありません。そのため、クライアントは通常、これを回避します。
package com.pluginx.api; import com.pluginx.internal.FooFactory; public class PluginXAPI { public static Foo getFoo() { return FooFactory.getFoo(); } }
APIは別のパッケージにあり、リフレクションを使用して実装クラスにアクセスします。APIは実装なしでコンパイルできます。リフレクションを使用すると、パフォーマンスが低下する可能性があります(ただし、問題がある場合はリフレクションオブジェクトをキャッシュできます。実装が利用できない場合の動作を簡単に制御できます。
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 } } }
APIは、インターフェースと抽象クラスのみで構成され、さらにクラスのインスタンスを取得する方法も含まれます。
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; } }
上記と同じですが、クライアントコードは別の場所から初期参照を取得する必要があります。
// 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();
しないでください。クライアントをプラグインに直接リンクさせる(ただし、非APIメソッドを呼び出せないようにする)。これにより、他の多くのプラグイン(およびほとんどのオープンソースプラグイン)が独自のラッパーを記述せずにこのプラグインのAPIを使用することが困難になります。