우리는 클라이언트가 응용 프로그램의 개별 인스턴스를 구성하기 위해 많은 수의 플러그 가능한 전략 (전략 인터페이스의 특정 구현)을 제공 할 수있게하는 API를 설계하고 있습니다. 또한 새 빌드가 필요없이 변경 가능하도록 인스턴스의 구성 파일에 정의 된 것을 선호합니다.Guice - 자신의 바인딩을 사용하여 유연한 플러그 가능 전략 구현을 지원하는 API를 제공하는 방법?
Google API를 쉽게 테스트하고 유지 관리 할 수 있도록 앞으로 Guice를 DI 프레임 워크로 사용합니다. 따라서 앞서 언급 한 전략은 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
인터페이스에 대한 다른 바인딩이있는 할 수 있습니다. 따라서 우리가 고려한 접근 방식은 모듈 인스턴스 자체가 구성에 지정되도록 허용하는 것입니다. 그러나이 방법에서는 두 개의 다른 모듈이 서로 다른 구현을 CountryStrategy
인터페이스에 바인딩하려고 시도 할 때 충돌이 발생합니다.
우리가 취하려고 생각하는 접근법은 클라이언트 개발자에게 전략 구현을 묶는 모듈을 격리한다는 보장을 제공하는 것입니다. 우리는 이러한 모듈 중 하나를 바인드하는 각 모듈에 대해 별도의 인젝터를 생성하는 설치 모듈을 가지고 있습니다 (HelloWorldStrategy
). 위의 예제에서, 이것은 다음과 같습니다.
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));
}
}
는 (설정에서 정의) 전략 모듈의 예제는 다음과 여기서이 작동하지만 효율적으로 시도하는 우리가 달성하려고하는지에 대한 약간의 과잉을 보인다
public class EuropeanCountryStrategyModule extends AbstractModule {
@Override
protected void configure() {
binder().bind(CountryStrategy.class).to(EuropeanCountriesStrategy.class);
binder().bind(HelloWorldStrategy.class).to(HelloCountry.class);
}
}
구성 기반 전략 패턴을 통합하십시오. 누구나 비슷한 문제를 겪거나 이러한 문제를 해결하기위한 모범 사례가 있습니까?
모든 의견을 크게 기뻐할 것입니다.
이 기사를 읽으면 많은 감사를드립니다.
감사합니다 - 나는 우리가 가지고있는 문제는 약간 다른 생각합니다. Google의 API는 자체 구현이나 내부 종속성에 대한 지식이 없어도 (또는 실제로 얼마나 많은 수의 구현이 있을지) 런타임에 이러한 전략을로드해야합니다. 따라서 두 전략이 동일한 구현 클래스이지만 내부 바인딩이 다른 경우 별도의 인젝터를 사용하지 않고도 충돌이 발생할 수 있습니다. 이것은 질문 제목에서 분명하지 않으므로 약간 수정했습니다. – pingfrog
당신은 각각의 전략을 인스턴스에 바인드 할 수 있고 (설정에 따라 객체를 인스턴스화 할 수있다) : bind (Service.class) .toInstance (new ServiceImpl ("some parameters")); bind (Service.class) .toInstance (new ServiceImpl 다른 매개 변수)); –