【问题标题】:What is the reasoning for separating the RestAdapter.build() and .create() methods when using Dagger?使用 Dagger 时分离 RestAdapter.build() 和 .create() 方法的原因是什么?
【发布时间】:2014-10-23 13:42:22
【问题描述】:

过去几个月我一直在使用 Dagger/Retrofit,并且看到了为 api 实现 ApiModule 类的常见模式。这些 ApiModule 通常看起来像这样:

@Provides @Singleton Client provideClient(OkHttpClient client) {
    return new OkClient(client);
  }

  @Provides @Singleton Endpoint provideEndpoint() {
    return "release".equalsIgnoreCase(BuildConfig.BUILD_TYPE)
        ? Endpoints.newFixedEndpoint(PRODUCTION_URL, "Foo Production Url")
        : Endpoints.newFixedEndpoint(STAGING_URL, "Foo Staging Url");
  }

  @Provides @Singleton Converter provideConverter(Gson gson) {
    return new GsonConverter(gson);
  }

  @Provides @Singleton RestAdapter provideRestAdapter(Endpoint endpoint, Client client,
      Converter converter) {
    return new RestAdapter.Builder()
        .setClient(client)
        .setEndpoint(endpoint)
        .setConverter(converter)
        .setLogLevel(BuildConfig.DEBUG
            ? RestAdapter.LogLevel.FULL
            : RestAdapter.LogLevel.NONE)
        .build();
  }

  @Provides @Singleton FooApi provideFooApi(RestAdapter restAdapter) {
    return restAdapter.create(FooApi.class);
  }

但是要清理它为什么不这样做:

@Provides @Singleton Client provideClient(OkHttpClient client) {
        return new OkClient(client);
      }

@Provides @Singleton Converter provideConverter(Gson gson) {
        return new GsonConverter(gson);
      }

@Provides @Singleton FooApi provideFooApi(Client client, Converter converter) {
    return new RestAdapter.Builder()
        .setClient(client)
        .setEndpoint("release".equalsIgnoreCase(BuildConfig.BUILD_TYPE)
            ? Endpoints.newFixedEndpoint(PRODUCTION_URL, "Foo Production Url")
            : Endpoints.newFixedEndpoint(STAGING_URL, "Foo Staging Url"))
        .setConverter(converter)
        .setLogLevel(BuildConfig.DEBUG
            ? RestAdapter.LogLevel.FULL
            : RestAdapter.LogLevel.NONE)
        .build()
        .create(FooApi.class);
  }

这样做有什么缺点还是我违反了 Dagger 合同?我之所以问是因为在某些情况下我需要在一个项目中使用多个 API……像上面的第二个示例那样设置它,就可以做到这一点。

【问题讨论】:

    标签: android architecture dependency-injection retrofit dagger


    【解决方案1】:

    这样做有三个原因:

    1. 通过拆分两者,您可以创建关注点分离。 RestAdapter 如何被实例化并放入图中与我们的服务接口实例如何放入图中完全分开。在这里,您碰巧将它们放在同一个模块中,但没有理由不能将它们放在单独的模块中,甚至没有理由不能将它们放在来自不同组件的库中。

    2. 单独的提供者允许您在覆盖模块中覆盖其中一个或两个以自定义行为,而不必知道另一个提供者的使用方式或来源。

      例如,如果您想在运行集成测试时启用不同的行为,您可以提供不同的 RestAdapter 实例。

      @Provides @Singleton RestAdapter provideTestRestAdapter() {
        return new RestAdapter.Builder()
            .setEndpoint(Endpoints.newFixedEndpoint("http://mycomputer.local/api"))
            .setLogLevel(FULL)
            .build();
      }
      

      将它放在覆盖模块中意味着您不必更改创建服务实例的位置。

    3. 最后,也是最简单的,也许你有多个服务接口。您不应创建多个 RestAdapter 实例(除非它们用于不同的端点)。

      @Provides @Singleton AccountService provideAccountService(RestAdapter ra) {
        return ra.create(AccountService.class);
      }
      
      @Provides @Singleton TweetService provideTweetService(RestAdapter ra) {
        return ra.create(TweetService.class);
      }
      
      @Provides @Singleton DirectMessageService provideDirectMessageService(RestAdapter ra) {
        return ra.create(DirectMessageService.class);
      }
      

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-05-28
      • 1970-01-01
      • 2019-12-06
      • 2017-06-09
      • 1970-01-01
      • 2017-04-10
      • 1970-01-01
      相关资源
      最近更新 更多