web-dev-qa-db-ja.com

依存性注入を伴うシングルトン、それはいくつかのケースで良い習慣ですか?

依存性注入を伴うシングルトン実装を用意することは良い考えですか? (データベースの読み込みに関連する)インスタンス化に関する重いタスクを実行するクラスがいくつかあります。常に新しいインスタンスとして使用したいのですが、パフォーマンスの問題があります。私が使用しているコードはレガシーアプリからのものであるため、あまり触れないでください。

私の質問は、この例のようにシングルトンを作成できますか?

[〜#〜]重要[〜#〜]:依存関係はロガーの一種であるため、複数の実装はありません。1つだけです。すべてのインスタンスが同じ依存関係のインスタンス化を共有している場合は問題ありません。

インターフェースを使用すると、プロジェクト間でソリューションの結合が少なくなるので、興味があります。

public class HeavyTaskDb()
{
   private static HeavyTaskDb instance;
   private IDependency dependency;

   private HeavyTaskDb(IDependency dependency)
   {
      this.dependency=dependency;
   }

   public static HeavyTaskDb Instance(IDependency dependency)
   {  
     if(instance==null)
     {
          instance=new HeavyTaskDb (dependency);}
     }
     return instance;
   }
}
5
X.Otano

あなたのプログラムが

_    HeavyTaskDb.Instance(X)
_

最初に、次に

_    HeavyTaskDb.Instance(Y)
_

後で(コードベースの完全に異なる領域にある可能性があります)、Xで初期化されたHeavyTaskDb型のオブジェクトを返しますが、Yでは期待どおりではありません。

これを回避する最善の方法は、おそらくシングルトンパターンをまったく使用せず、htdb=new HeavyTaskDb(X)を含む1回の初期化を1つの定義済み配置で実行し、htdbオブジェクトをすべてのスコープで使用できるようにすることです。それは必要です(おそらくそれを渡すことによって、おそらくそれを使用中のクラスに注入することによって、関連するコンテキストで最も意味のあるものは何でも)。

(シングルトンがグローバル変数であるように)プログラムにHeavyTaskDbタイプのグローバル変数が必要だと本当に思っている場合は、次のように実装することを検討してください。

_public class HeavyTaskDb()
{
   private static HeavyTaskDb instance;
   private IDependency dependency;

   private HeavyTaskDb(IDependency dependency)
   {
      this.dependency=dependency;
   }
   // call this somewhere at the beginning of the program,
   // before Instance get called
   public static void InitInstance(IDependency dependency)
   {
         instance=new HeavyTaskDb (dependency);
   }

   public static HeavyTaskDb Instance()
   {  
     if(instance==null)
     {
          throw new Exception("instance was forgotten to be initialized")
     }
     return instance;
   }
}
_

これはまだ理想的な解決策ではありませんが、少なくとも_HeavyTaskDb.Instance_の呼び出し元は、彼が得るものについてだまされません。

9
Doc Brown