1

我是 Google Guice 的新手,我正在努力思考如何在我的特定场景中使用它。我正在构建一个非常复杂的服务客户端,并且(我相信)确实需要正确实例化构建器模式。因为这个客户端最终会被打包到它自己的 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应该注入*ResourceImpls
  • 每个都*ResourceImpl应该注入一个*Command实例

预期的用例是使构建MyClientimpl 变得简单:

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);
    }
}

但是对于我的生活,我看不到如何/在哪里:

  • 将 s绑定*Command*ResourceImpls;和
  • *ResourceImpl将s绑定到MyClientImpl实例

有任何想法吗?

4

1 回答 1

3

目前尚不清楚您要通过注射完成什么。通过将其与构建器和设计的其他方面联系起来,您可能会进一步混淆问题。我建议您将您的代码剥离到一个SSCCE,该 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();
  }
}

此界面的 Guicified 用户:

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 模块中,而不是运行时代码中。运行时代码包含的唯一内容是创建注入器时模块的使用。您可以为 bar 服务创建一个新模块并使用它来创建注入器,或者您可以更改主服务模块中的绑定。

一旦你理解了上面发生的事情,你应该能够通过在你希望被 Guice 注入的每个实例上重复这些概念来解决你自己的代码中的任何问题。

于 2014-11-27T21:05:54.873 回答