2017-03-11 21 views
1

私はGuiceに関連し、Guice以外のシングルトンを避けるというわずかなジレンマがあります。マルチモジュールプロジェクトでは、sharedfrontendbackendの3つのモジュールがあるとします。 frontendbackendの両方は、sharedモジュールの内部でProfilingクラスのインスタンスを使用します(これはメソッドを実行し、プロジェクト全体で広く使用されます)。マルチモジュール環境での依存性注入(Guice経由)の使用

ほとんどすべてのクラスでこのProfilingインスタンス(ユーザーが接続すると、オブジェクトは動的に作成されます)を使用する必要があります。

すべての単一のクラスがProfilingクラスのインスタンスを必要とする場合、それを行うためのさまざまな方法には欠点があります(インスタンスフィールドにコピーコンストラクタでは、)

解決方法1:

private final Profiling profiling; 

@Inject 
public User(Profiling profiling, String username) 

欠点:すべて012コンバーターのProfilingオブジェクトを含める必要があります。これは面倒で、やや意味がありません。また、GuiceのInjectorを静的に(または注入して)保存して、プログラムが最初にロードされたときだけでなく、オンザフライでUserオブジェクトを作成できるようにする必要があります。 (唯一のインスタンスフィールドなど)

解決方法2:

@Inject 
private Profiling profiling; 

public User(String username) 

欠点:上記と同様に、あなたはすべての単一のオブジェクトをインスタンス化するために、GuiceののInjectorを使用する必要があります。つまり、Userのオブジェクトを動的に作成するには、Userオブジェクトを作成するクラスにインジェクタのインスタンスが必要です。

public static final Profiling PROFILING; // Can also use a get method 

public Application() { 
    Application.PROFILING = injector.getInstance(Profiling.class) 
} 

欠点(米国によって手動で作成した(メイン)クラスの静的フィールドのような)解決策3:Guiceの者/依存性注入の推奨に反する - 静的にアクセスされるシングルトンProfilingオブジェクトを作成(によってApplication.PROFILING.start())Guiceの目的を破る? (Guiceので注入されたすべての単一のクラスの静的フィールド、など)

ソリューション4

@Inject 
private static Profiling profiling; 

// You need to request every single class: 
// requestStaticInjection(XXXX.class) 

欠点:それは静的に注入されているのでここでも、これはGuiceのの/依存性注入の推奨事項に反します。 GuiceがProfilerを注入する必要があるすべてのクラスをリクエストする必要もあります(面倒です)。

私のプロジェクトを設計し、私が使用していたシングルトンのデザインパターンに落ちないようにする良い方法はありますか?

TL; DR:シングルトンデザインパターンに落ちることなく、すべての単一のクラスでこのプロファイリングインスタンス(モジュールごとに1つ)にアクセスできるようにしたい。

ありがとうございます!

+1

あなたが提案した(静的ではない)任意のguice管理クラスに注入します。コンストラクタインジェクションのみを使用します(手動コンストラクションは同じ引数を渡さなければならず、無効なインスタンスを作成することはできません)。しかし、ユーザはguice管理クラスのようには聞こえません。私は(おそらく、そこに十分な情報がありません)、プロファイリングクラスをインジェクトでき​​るユーザーファクトリを実装し、各ユーザーにプロファイリングインスタンスを持つという問題を抽象化して実装します。 – pandaadb

答えて

2

実際には、通常のシングルトンを使用します。おそらく、単一フィールドの列挙型または類似のパターンを使用します。

なぜかを知るには、Guiceの目的は何か、そして依存性注入の一般的な目的は何ですか?目的は、アプリケーションの部分を切り離して、独自に開発してテストし、一元的に構成および再配置できるようにすることです。そのことを念頭に置いて、のカップリングコストに対して秤量する必要があります。デカップリングのコストはです。これは、カップルまたはデカップリングするオブジェクトによって異なります。

ここでは、ユーザーのようなモデルオブジェクトを含むテストなど、実際に動作するプロファイリングのインスタンスがなくてもアプリケーションを操作できないというコストがかかります。その結果、Profilingがその環境(例えば、高解像度システムタイミング呼び出しの可用性)に関して何らかの前提条件を設定した場合、プロファイリングを無効にせずにUserのようなクラスを使用することはできません。さらに、テスト分離のために新しい(シングルトンではない)プロファイリングインスタンスでテストをプロファイルしたい場合は、それを個別に実装する必要があります。ただし、プロファイリングクラスが軽量で十分な負担をかけない場合は、引き続きこの方法を選択できます。

デカップリングのコストは、すべてのオブジェクトを強制的にan injectable, as opposed to a newableにすることができるということです。クラスとテストで新しい/ダミー/偽のプロファイリングの実装を代用し、別のコンテナで異なるプロファイリングの振る舞いを使用するように再構成することができます。ただし、その柔軟性は、それらの実装。後で作成されるUserのようなクラスでは、Guice assisted injectionまたはAutoFactory code generationによって提供されるような、ファクトリの実装を追求する必要があります。 (あなたはそれ以外の場合は注入、および工場のインスタンスを注入すると、選択したgetパラメータを取るためにプロバイダーをカスタマイズするようになることでしょう任意のオブジェクトのためにProvider<T>の代わりTを注入することによって、任意の数のオブジェクトを作成することができることを覚えておいてください。)

についてあなたのソリューション:

  • 溶液1および2、オブジェクトごとの注入:工場が輝くだろう場所です。 (私はコンストラクタインジェクションを好むだろうが、その選択肢があるので、それらの間のソリューション1を考えてみよう)もちろん、新しいユーザを作成するすべてのものはUser.Factoryを注入する必要があるので、厳密にスコープされたプロジェクトあなたのコードベースのすべてのクラスをDIに変換するプロジェクトに変換します。これはあなたが今やっていることには容認できないコストとなるかもしれません。依存性注入によって作成されていないオブジェクトの場合は、単一のクラスの静的注入を要求し、ProfilingHolderまたはsomesuchのように:メインホルダーの静的注入を要求

    // Nested interface for your Factory: 
    public interface Factory { User get(String username); } 
    
    // Mark fields that the user provides: 
    @Inject public User(Profiling profiling, @Assisted String username) { ... } 
    
    // Wire up your Factory in a Module's configure: 
    install(new FactoryModuleBuilder().implement(User.Factory.class)); 
    
    // Now you can create new Users on the fly: 
    @Inject User.Factory userFactory; 
    User myNewUser = userFactory.get("timothy"); 
    
  • ソリューション3は、私が考えていたものに近いです。あなたも、それを柔軟性のためにノーオペレーションの振る舞いを与えることができる:もちろん

    public class ProfilingHolder { 
        // Populate with requestStaticInjection(ProfilingHolder.class). 
        @Inject static Profiling profilingInstance; 
        private ProfilingHolder() { /* static access only */ } 
        public static Profiling getInstance() { 
        if (profilingInstance == null) { 
         // Run without profiling in isolation and tests. 
         return new NoOpProfilingInstance(); 
        } 
        return profilingInstance; 
        } 
    } 
    

    を、あなたはVMのシングルトンへの呼び出しに頼っている場合、あなたが本当にちょうどで、通常のVM-グローバル静的なシングルトンパターンを採用しています可能であればGuiceを使用するための相互作用。あなたはこのパターンを簡単に回して、Guiceモジュールbind(Profiling.class).toInstance(Profiling.INSTANCE);を持っていて、同じ効果を得ることができます(ProficeはGuiceなしでインスタンス化できると仮定します)。

  • ソリューション4では、すべての単一クラスのrequestStaticInjectionは私が考慮しない唯一のものです。クラスのリストが長すぎると、それらが変化する可能性はProfilingが細すぎます。貴重な設定ではなくモジュールをメンテナンスコストの高い食料品リストにすると、カプセル化を中断したり、Guiceを使ってテストしたりすることになります。

ので、要約すると、私はGuiceのシングルトンあなたの現在の注射用オブジェクトのための注入、あなたの現在のnewableオブジェクトのための通常のシングルトン、および工場IF /どんなのに移行するオプションを選択したいあなたnewables注射薬への飛躍になります。