Я новичок в Google Guice, и я пытаюсь оборачивать голову тем, как использовать его для моего конкретного сценария. Я создаю клиентский сервис, который довольно сложный и что (я считаю) действительно требует правильного создания шаблона Builder. Поскольку этот клиент в конечном итоге будет упакован в свою собственную JAR-библиотеку, я бы хотел, чтобы Guice обрабатывал DI под капотом. Ниже приведена очень упрощенная версия моего кода:
public interface MyClient {
public FizzResource getFizzResource();
public BuzzResource getBuzzResource();
public FooResource getFooResource();
}
public class MyClientImpl implements MyClient {
// See below
}
public class GetFizzCommand {
// omitted for brevity
}
public class GetBuzzCommand {
// omitted for brevity
}
public class GetFooCommand {
// omitted for brevity
}
public interface FizzResource {
Fizz getFizz(Long fizzId);
}
public class FizzResourceImpl implements FizzResource {
private GetFizzCommand getFizzCommand;
@Override
Fizz getFizz(Long fizzId) {
return getFizzCommand.doGetFizz(fizzId);
}
}
public interface BuzzResource {
Buzz getBuzz(Long buzzId);
}
public class BuzzResourceImpl implements BuzzResource {
private GetBuzzCommand getBuzzCommand;
@Override
Buzz getBuzz(Long buzzId) {
return getBuzzCommand.doGetBuzz(buzzId);
}
}
public interface FooResource {
Foo getFoo(Long fooId);
}
public class FooResourceImpl implements FooResource {
private GetFooCommand getFooCommand;
@Override
Foo getFoo(Long fooId) {
return getFooCommand.doGetFoo(fooId);
}
}
Таким образом, вы можете видеть, что график иерархии/депо выглядит следующим образом:
MyClient
следует вводить *ResourceImpl
s*ResourceImpl
следует вводить экземпляр *Command
Предполагаемый прецедент - сделать создание MyClient
impl максимально простым:
MyClient myClient = MyClientImpl.Builder("myservice.example.org", 8080L, getWidget())
.withAuth("user", "password")
.withHttps()
.withFailureStrategy(someFailureStrategy)
// ...etc.
.build();
Итак, вот моя лучшая попытка в MyClientImpl
, его внутреннем застройщике и модуле Guice:
public class BaseClient {
private String uri;
private long port;
private Widget widget;
// ctor, getters and setters
}
public class MyClientImpl extends BaseClient implements MyClient {
@Inject
private FizzResource fizzResource;
@Inject
private BuzzResource buzzResource;
@Inject
private FooResource fooResource
public MyClientImpl(String uri, long port, Widget widget) {
super(uri, port, widget);
}
public static class Builder {
private String uri;
private long port;
private Widget widget;
Builder(String uri, long port, Widget widget) {
super();
setUri(uri);
setPort(port);
setWidget(widget);
}
// Lots of methods on the builder setting lots of MyClient-specific properties
// that I have omitted here for brevity.
MyClient build() {
Injector injector = Guice.createInjector(new MyClientModule(this));
return injector.getInstance(MyClient.class);
}
}
}
public class MyClientModule extends AbstractModule {
private MyClientImpl.Builder builder;
public MyClientModule(MyClientImpl.Builder builder) {
super();
setBuilder(builder);
}
@Override
protected void configure() {
MyClientImpl myClientImpl = new MyClientImpl(builder.getUri(), builder.getPort(), builder.getWidget());
bind(MyClient.class).toInstance(myClientImpl);
}
}
Но для моей жизни я не вижу, как и где:
*Command
к *ResourceImpl
s; а также*ResourceImpl
к экземпляру MyClientImpl
Есть идеи?
Это не совсем ясно, что вы пытаетесь выполнить с помощью ваших инъекций. Возможно, вы путаете этот вопрос, сделав его о строителях и других аспектах вашего дизайна. Я предлагаю вам разбить код на SSCCE, который функционирует, но не включает в себя инъекцию, а затем увеличит ваш дизайн, введя, например, одно поле. Прямо сейчас все ваши показания кода - это обрезанный скелет сложного дизайна с инъекциями, который не имеет смысла, и нет способа запустить код и посмотреть, что произойдет. Guice работает во время выполнения, поэтому важно, чтобы мы видели ваш main
метод, чтобы увидеть, что на самом деле делает ваш код приложения.
Ниже следует очень простой пример того, что я описал выше.
Интерфейс с двумя разными типами:
public interface Service {
void useService();
}
public class FooService implements Service {
public void useService() {
System.out.println("foo service used");
}
}
public class BarService implements Service {
public void useService() {
System.out.println("bar service used");
}
}
Пользователь ванили (не-Guice) этого интерфейса:
public class ServiceUser {
Service service = new FooService(); // change impl to be used here
public static void main(String[] args) {
new ServiceUser().service.useService();
}
}
Указанный пользователь этого интерфейса:
public class ServiceUserGuicified {
@Inject
Service service;
public static void main(String[] args) {
Injector injector = Guice.createInjector(new FooServiceModule());
ServiceUserGuicified user = injector.getInstance(ServiceUserGuicified.class);
user.service.useService();
}
}
public class FooServiceModule extends AbstractModule {
@Override
protected void configure() {
bind(Service.class).to(FooService.class);
}
}
В версии Guicified определение impl кодируется в модуле Guice, а не во время выполнения кода. Единственное, что включает код выполнения, это использование модуля при создании инжектора. Вы можете создать новый модуль для обслуживания бара и использовать его для создания инжектора или изменить привязку в своем основном сервисном модуле.
Как только вы поймете, что происходит выше, вы сможете решить любые проблемы в своем собственном коде, повторив концепции на каждом экземпляре, который вы хотите ввести Guice.
Command
сResource
, и при этом это не имеет смысла, поскольку они не являются частью одной иерархии типов. Кроме того, у вас нетCommand
@Inject
ed поэтому ее не нужно привязывать. То же самое касается вашей другой точки пули.Command
сResource
, и при этом это не имеет смысла, поскольку они не являются частью одной иерархии типов. Кроме того, у вас нетCommand
@Inject
ed поэтому ее не нужно привязывать. То же самое касается вашей другой точки пули.