2016-03-18 10 views
12

私は怠け者で、フィールド注射をほとんど使用していました。空のコンストラクタを提供していただけで、私の@Injectフィールドを置いてみました。しかしフィールドインジェクションにはトレードオフがあるので、いつフィールドを使うのか、いつコンストラクタインジェクションを使うのかを決めるのに役立つ簡単なルールを考案しました。私のロジックに間違いがある場合、または追加する追加の考慮事項がある場合は、いかなるフィードバックも感謝します。ダガー2:コンストラクタインジェクションをいつ使うのか、フィールドインジェクションをいつ使うのですか?

同じページ上にあるために、まずいくつかの明確化:

コンストラクタ・インジェクション:

@Inject 
public SomeClass(@Named("app version") String appVersion, 
        AppPrefs appPrefs) {... 
フィールド注入と同じ

public class SomeClass { 
    @Inject 
    @Named("app version") String mAppVersion; 

    @Inject 
    AppPrefs appPrefs; 

はルール1:フィールドを使用しなければなりません私がオブジェクトの作成を制御しない場合は、注入()(Androidのアクティビティやフラグメントと考える)私のオブジェクトを作成し、それを私に処理するフレームワーク(非ダガー認識)のフレームワークでは、インスタンスを受け取った後に手動で注入するしかありません。

ルール2:Dagger 2を使用しない別のプロジェクトでクラスを使用する場合は、コンストラクタインジェクションを使用する必要があります。他のプロジェクトでDaggerを使用しない場合はDIを使用できないため、ユーザはnewを使用してオブジェクトを「古い」方法で作成する必要があります。

ルール3:単体テストの作成が容易であるため、クラス階層を扱うときはPREFERコンストラクタを注入します。

明確化:

package superclass; 

public class SuperClass { 
    @Inject 
    HttpClient mHttpClient; 
    ... 
} 

フィールドインジェクションを使用して、以下の構造を考えます。

package differentpackage; 

public class SubClass extends SuperClass { 
    public SubClass() { 
    } 
} 

私はディレクトリtest/java/differentpackageに​​ためのユニットテストを作成していたとき、私はHttpClientを注入することができるようにするために全体のDIインフラを立ち上げざるを得ません。私はこのようなコンストラクタ・インジェクション使用していた場合はこれとは対照的に、:私のユニットテストで

public class SuperClass { 
    private final HttpClient mHttpClient; 

    @Inject 
    public SuperClass(HttpClient httpClient) { 
     mHttpClient = httpClient; 
    } 
} 

を私は単純にできます

HttpClient mockHttp = mock(HttpClient.class); 

Subclass tested = new Subclass(mockHttp); 

// tests 

だから基本的に今私は他の極端に午前:私は主に依存する傾向がありますコンストラクタインジェクションを行い、フィールドインジェクションを使用するのは、 'Rule 1'が適用された場合のみです。私はコンストラクタで持っている唯一の「問題」は注入 は、「終了」のクラスのコンストラクタは、時にはかなりのパラメータで過負荷になっていることであり、彼らはこのように冗長と醜い:

@Inject 
public ModelMainImpl(@Named("app version") String appVersion, 
        AppPrefs appPrefs, 
        LoginPrefs loginPrefs, 
        @ForApplication Context appContext, 
        NetworkInfoProvider networkInfoProvider, 
        AndroidEventPoster androidEventPoster, 
        Session session, 
        ForgeExchangeManager exchangeManager, 
        HttpFunctionality httpFunctionality, 
        @Named("base url") String baseUrl, 
        @Named("forge result producer") ResultProducer<ForgeExchangeResult> resultProducer 
        ) { 

みんな、あなたのルールには何ですかコンストラクタとフィールドインジェクションのどちらかを選択しますか?私は何かが欠けている、私のロジックにエラーがありますか?

+0

https://stackoverflow.com/questions/39207845/android-dagger-2-inject-versus-provides これを見ると、良い洞察を提供します –

答えて

5

コンストラクタインジェクションを使用します。できない場合は、プロパティインジェクションを使用します。

ルール1は、装飾や属性のように、プロパティ(フィールド)注入を使用できます。

ルール2は、あなたのクラスを使用する人がコンストラクタに従わなければならないので、大丈夫です。彼らはまたあなたの財産をintilaizeしなければならないことを知らないかもしれません。

ルール3単体テストには適していません。それは単一責任を適用するのに適しています。あなたのオブジェクトグラフを見るのが簡単です。そうでなければ、それをプロパティで隠すでしょう。

私たちがあなたの質問に来たら、はい、あなたのコンストラクタに多くのパラメータがあります。しかし、ソリューションはプロパティの注入ではありません。あなたのコードをリファクタリングして使用することができますaggregate services

関連する問題