2016-09-12 37 views
5

在模塊內部,如果我需要根據模塊構建時已知的變量提供不同的接口實現,我可以將該邏輯放置在該接口類型的@Provides方法中。像這樣:如何告訴Dagger 2根據X實例化哪個實現?

@Module 
public class FooModule { 

    private final State state; 

    public FooModule(State state) { 
     this.state = state; 
    } 

    @Provides 
    FooInterface provideFooImplementation() { 
     switch(state) { 
      case STATE_1: 
       return new FooImpl1(); 
      case STATE_2: 
       return new FooImpl2(); 
      ... 
      case STATE_10: 
       return new FooImpl10(); 
     } 
    } 
} 

但是,這些實現可以由Dagger創建。我寧願說「嗨,基於X我想讓你爲我實例化這個類」

我已經考慮了幾個選項。

  1. 更改提供方法採取所有可能的實現:

    @Provides 
    FooInterface provideFooImplementation(FooImpl1 impl1, FooImpl2 imp2, ..., FooImpl10 impl10) { 
        switch(state) { 
         case STATE_1: 
          return impl1; 
         case STATE_2: 
          return impl2; 
         ... 
         case STATE_10: 
          return impl10; 
        } 
    } 
    

這使得匕首實例化他們,滿足他們所有的依賴關係,但它不是,如果每一個好主意的實現相對較大或昂貴。

  1. 更改提供方法以獲取不同實現的所有依賴關係的集合。

    @Provides 
    FooInterface provideFooImplementation(Context context, Repo repo, HttpClient httpClient, ...) { 
        switch(state) { 
         case STATE_1: 
          return new FooImpl1(context); 
         case STATE_2: 
          return new FooImpl2(repo, httpClient); 
         ... 
         case STATE_10: 
          return new FooImpl10(context, repo); 
        } 
    } 
    

這比在匕首選擇1稍微好一點不必實例化每一個執行,但它仍然需要實例所有,即使他們可能不會在所有情況下使用的依賴關係。即使可以由Dagger創建,我也可以自己創建對象。

  1. 爲每個實現創建一個模塊並實例化相應的模塊。因此,像:

    @Module 
    public FooImpl1Module { 
    
        @Provides 
        FooInterface provideFooImplementation(Context context) { 
         return new FooImpl1(context); 
        } 
    } 
    

這將是罰款,但現在我有界定取決於模塊組件的問題。

解決此問題的最佳方法是什麼?

一個建議是嘗試選項1,參數包含在Lazy中。然後我只能在一個上調用.get()。我會盡我所能,併發布結果

+0

你有沒有使用組件提供方法或'@ Named'註釋手動考慮? – EpicPandaForce

+0

EpicPandaForce,@本身不起作用,因爲依賴對象不知道它需要哪個實現。組件提供方法是什麼意思? –

回答

1

不是Lazy<T>,做選擇1 Provider<T>Lazy<T>只是一個Provider<T>,它在本地記憶(具有必要的雙重檢查鎖定),但因爲您知道只會調用一次提供程序,所以您可以直接注入提供程序並跳過同步開銷。

@Provides 
FooInterface provideFooImplementation(
     Provider<FooImpl1> impl1, 
     Provider<FooImpl2> impl2, 
     ..., 
     Provider<FooImpl10> impl10) { 
    switch(state) { 
     case STATE_1: 
      return impl1.get(); 
     case STATE_2: 
      return impl2.get(); 
     ... 
     case STATE_10: 
      return impl10.get(); 
    } 
} 

選項2會的工作,但你會有效地跳過依賴佈線那匕首可以很容易地爲你做的,因爲你的@Component註釋需要你的模塊列表中的規定選擇3都不行您的Dagger代碼生成工作的編譯時常量。如果你的綁定是一個常量或一個形式的零依賴類,那麼你可以將你的Module的任意一個子類傳遞給你的Component構建器, Dagger只能分析超類模塊中的綁定,如果您的@Provides方法實現的參數與您的參數不同,那麼您將遇到麻煩,因此switch是我能想到的最好,最清晰的替代方案。)

+0

對不起我的無知,但讓我們說,如果我去選擇1,當單擊按鈕時,我想交換'FooInterface'的實現,我將不得不重新創建提供'FooInterface'的整個'Component',wouldn'我呢?如果是這樣,這聽起來有點昂貴......另外,我怎麼能在已經重新創建的'Component'中保留其他依賴關係的狀態? – Leo

+0

@Leo最初的問題詢問在模塊創建時已知的常量,所以是的,這就是你必須爲上述做的事情。如果您想從同一個組件返回不同的值,您可以(1)在創建模塊後更改模塊中的值,(2)讓您的'@ Provide'方法注入值或值 - (3)你可以注入一個工廠[像這個Guice等價物](http://stackoverflow.com/a/24071727/1426891)。我贊成#3,因爲在組件創建後更改注入綁定變得棘手。 –

+0

啊,對不起,我錯過了(我在運行時使用Google搜索實現,然後我到了這裏)。無論如何,如果我理解正確,在(1)和(2)中我必須重新創建'Component',並在使用'FooInterface'的地方重新注入。對於(3),我認爲不需要重新創建和重新注入,但是我必須提前提供'FooInterface'的所有實現,如果我在工廠對象中使用Lazy不同的實現,這是一個好主意嗎? – Leo

-4

你試過類似的東西嗎?

public class hectic extends Iam { 

    String tokenizer heccas = new string tokenizer(); 
} 
3

一個可能的解決方案將使用@Named("foo")註釋結合了手動進樣,這不過意味着你的狀態會是獨立模塊本身有利於部件供給方法,你會是一個讓你的選擇

@Component(modules={FooModule.class}) 
public interface AppComponent { 
    @Named("STATE_1") 
    FooInterface fooImpl1(); 
    @Named("STATE_2") 
    FooInterface fooImpl2(); 
    ... 
    @Named("STATE_10") 
    FooInterface fooImpl10(); 
} 

@Module 
public FooImpl1Module { 
    @Provides 
    @Named("STATE_1") 
    FooInterface provideFooImpl1(Context context) { 
     return new FooImpl1(context); 
    } 

    @Provides 
    @Named("STATE_2") 
    FooInterface provideFooImpl2(Context context) { 
     return new FooImpl2(context); 
    } 

    ... 

    @Provides 
    @Named("STATE_10") 
    FooInterface provideFooImpl10(Context context) { 
     return new FooImpl10(context); 
    } 
} 

然後就可以調用

FooInterface fooInterface = component.fooImpl1(); 
相關問題