簡體   English   中英

使用Builder模式的客戶端lib的Guice注入

[英]Guice injection with Builder pattern for client lib

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

因此,您可以看到層次結構/ dep圖如下:

  • MyClient應注入*ResourceImpl
  • 每個*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 s綁定到*ResourceImpl ;
  • *ResourceImpl綁定到MyClientImpl實例

有任何想法嗎?

目前還不清楚你注射的是什么。 您可能會因為關於構建器和設計的其他方面而進一步混淆此事。 我建議你將代碼剝離到一個功能但不包含任何注入的SSCCE ,然后通過注入一個字段來增加你的設計。 現在你所有的代碼展示都是復雜設計的修剪骨架,注入沒有意義,沒有辦法運行代碼,看看會發生什么。 Guice在運行時運行,因此我們必須看到您的main方法,以查看應用程序代碼實際執行的操作。

下面是我上面描述的一個非常簡單的例子。

具有兩個不同impl的接口:

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

此接口的vanilla(非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注入的每個實例的概念來解決你自己代碼中的任何問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM