私たちは、クライアントがアプリケーションの個々のインスタンスを構成するために、数多くのプラガブル戦略(戦略インタフェースの特定の実装)を提供できるようにするAPIを設計しています。さらに、新しいビルドを必要とせずに変更可能にするために、これらをインスタンスの構成ファイルで定義することをお勧めします。Guice - 独自のバインディングで柔軟なプラグイン可能な戦略実装をサポートするAPIを提供する方法
私たちのAPIを容易にテスト可能で保守可能にするため、私たちはDIフレームワークとしてGuiceを使用しています。したがって、前述の戦略は、アプリケーションの特定のインスタンスに対して任意の数の実装が存在することができるため、Multibinder拡張を介してバインドされます。各戦略には識別子が関連付けられているため、戦略識別子 - >戦略実装クラスをマップするマップバインダーに追加されます。
このアプローチで問題となっているのは、これらの戦略自体が戦略パターンを利用する可能性があるということです。したがって、これらの戦略を同じクラスのインスタンスにすることはできますが、異なる依存実装を注入することができます。戦略は独自のバインディングを設定することができますが、これは同じインタフェースの異なる実装をバインドしようとします(これはロボットの脚の問題と似ていますか?)
簡単な例を挙げてみましょうAPIはコンフィグレーションで定義されたHelloWorld
の戦略に依存していました。これらの戦略は次のインタフェースの実装でした。
public interface HelloWorldStrategy {
public String getMessage(String caller);
}
「プラグイン可能」コードでは、次の実装があります。私たちの設定ファイルで
public class HelloWorld implements HelloWorldStrategy {
public String getMessage(String caller) { return "Hello World"; }
}
public class HelloCountry implements HelloWorldStrategy {
private final CountryStrategy countryStrategy;
@Inject
public HelloCountry(CountryStrategy countryStrategy) {
this.countryStrategy = countryStrategy;
}
public String getMessage(String caller) {
return "Hello " + countryStrategy.getCountry(String caller);
}
}
我々はHelloCountry
クラスの複数のインスタンスを定義したいがCountryStrategy
インターフェイスごとに異なるバインディングを持っていることがあります。したがって、私たちが検討しているアプローチは、Moduleインスタンス自体を設定で指定できるようにすることです。しかし、このアプローチでは、異なる2つのモジュールが異なる実装をCountryStrategy
インターフェイスにバインドしようとすると、衝突が発生します。
私たちが取り組んでいるアプローチは、クライアント開発者に、ストラテジ実装をバインドするモジュールが分離されているという保証を提供することです。私たちは、HelloWorldStrategy
のこれらの実装の1つをバインドするモジュールごとに別々のインジェクタを作成するセットアップモジュールを用意することによってこれを行います。上の例では、これは以下のようになります。
public class EuropeanCountryStrategyModule extends AbstractModule {
@Override
protected void configure() {
binder().bind(CountryStrategy.class).to(EuropeanCountriesStrategy.class);
binder().bind(HelloWorldStrategy.class).to(HelloCountry.class);
}
}
これが効果的にしようとしている私たちが達成しようとしているもののために少しやり過ぎを、動作しますが、そうです:(設定で定義された)戦略モジュールの一例は以下のようになり
public class HelloWorldStrategySetupModule extends AbstractModule {
private final List<HelloWorldStrategyModule> strategyModules;
private final Injector parentInjector;
public HelloWorldStrategySetupModule(List<HelloWorldStrategyModule> strategyModules, Injector parentInjector) {
this.strategyModules = strategyModules;
this.parentInjector = parentInjector;
}
@Override
protected void configure() {
MapBinder<String, HelloWorldStrategy> mapbinder = MapBinder.newMapBinder(binder(), String.class, HelloWorldStrategy.class);
for(HelloWorldStrategyModule strategyModule : strategyModules) {
Injector strategyModuleInjector = parentInjector.createChildInjector(strategyModule);
mapbinder.addBinding(strategyModule.getIdentifier()).toInstance(strategyModuleInjector.getInstance(HelloWorldStrategy.class));
}
}
構成ベースの戦略パターンを組み込む。誰もが同様の問題に遭遇したか、またはこれらの問題を解決するベストプラクティスの方法を持っていますか?
ご意見は大変ありがとうございます。
あなたがこれを遠くに持っていれば、読んでいただきありがとうございます。
感謝を - 私たちは持っている問題は、わずかに異なっていると思います。私たちのAPIは、独自の実装や内部的な依存関係(実際にどれくらいの数があるか)を知らなくても、実行時にこれらの戦略をロードする必要があります。したがって、2つのストラテジが同じインプリメンテーションクラスを持ち、内部バインディングが異なる場合は、別々のインジェクタを使用せずに衝突する可能性があります。これは質問のタイトルからは分かりませんので、少し修正しました。 – pingfrog
バインド(Service.class).toInstance(新しいServiceImpl( "some parameters"));バインド(Service.class).toInstance(新しいServiceImpl( "some異なるパラメータ)); –