web-dev-qa-db-ja.com

静的クラスの代わりにシングルトンを使用するのはなぜですか?

シングルトンが静的クラスより実際に簡単または優れているのはいつですか?シングルトンを作成することは、実際には必要ではない余分な労力であるように思えますが、それには十分な理由があると確信しています。そうでなければ、明らかに、それらは使用されません。

40

静的クラスよりもシングルトンを優先する1つの理由は(自由に使えるより良いパターンがないと仮定して;))、あるシングルトンインスタンスを別のインスタンスと交換することです。

たとえば、次のようなロギングクラスがあるとします。

public static class Logger {
    public static void Log(string s) { ... }
}

public class Client {
    public void DoSomething() {
        Logger.Log("DoSomething called");
    }
}

これは本当にうまくいきますが、ロガーがデータベースに何かを書き込んだり、コンソールに出力を書き込んだりするとどうなりますか。テストを作成している場合、おそらくこれらすべての副作用を望まないでしょう。しかし、logメソッドは静的なので、それ以外は何もできません。

さて、テストのためにLogメソッドをホットスワップしたいと思います。ガジェットシングルトンに行きましょう!

public class Logger {
    private static Logger _instance;
    public static Logger Instance
    {
        get
        {
            if (_instance == null)
                _instance = new Logger();
            return _instance;
        }
        set { _instance = value; }
    }
    protected Logger() { }
    public virtual void Log(string s) { ... }
}

public class Client {
    public void DoSomething() {
        Logger.Instance.Log("DoSomething called");
    }
}

したがって、TestLogger : Logger空のLogメソッドを使用して、テストロガーのインスタンスをテスト用のシングルトンインスタンスに設定します。プレスト!クライアントコードに影響を与えずに、ロガーの実装をテストまたは実稼働用にホットスワップできます。

29
Juliet

以下の理由により、シングルトンはグローバル変数よりも好まれます。

  • それらは、グローバル名前空間(または、名前空間を持つ言語では、それらを含む名前空間)を不要な変数で汚染しません。
  • 多くの言語のグローバル変数は常にリソースを消費しますが、それらは遅延割り当てと初期化を許可します。

ソース

編集:

シングルトンのクールな使用法の1つは、ファクトリメソッドと組み合わせると、 フライウェイトパターン を作成するために使用できることです。これは、新しいオブジェクトを作成するときに、ファクトリが(新しいオブジェクトを作成する代わりに)最初にそのオブジェクトのシングルトンがすでに作成されていることを確認します。作成されている場合は、そのオブジェクトを返すだけです。そうでない場合は、新しいシングルトンを作成します。作成したシングルトンを追跡しながら、それを返します。フライウェイトは、シングルトンの不変性のために機能します。

10
Ryan Hayes

シングルトンはいつも私には少し冗長に見えました。私は静的クラスを好み、異なる動作が必要な場合は、依存関係の注入とプロバイダーと組み合わせます。これがどのようなパターンであるか、または名前があるかどうかはわかりませんが、通常は次のようになります。

public interface IFooProvider {
  Bar FooBar();
}

public static class Foo {
  public static readonly IFooProvider FooProvider { get; set; }
  public Bar FooBar() { return FooProvider.FooBar(); }
}

次に、プロバイダーをinitメソッドのどこかに設定するようにします。クラスの初期化時にデフォルトのプロバイダーを設定する場合は、遅延初期化を追加するのは簡単です。何よりも、静的クラスを使用する美学を維持しながら、動作を変更することができます。

6
David Smith

IMHOのシングルトンパターンはかなり使い古されたパターンですが、次のような利点がある場合があります。

  • インスタンスとして(同じベースから継承する)さまざまな種類のオブジェクトを使用する機能(たとえば、ファイルシステムとSQLデータベースを使用するデータプロバイダーを考えてみてください)
  • 直列化可能性。静的クラスを自動的にシリアル化できるフレームワークは使用していません。
  • 静的フィールドの使用。一部の人々にとって、これはより審美的な機能ですが、場合によっては実用的な利点があります。
5
Matti Virkkunen

多くの言語では、静的クラスには、継承(およびより一般的にはポリモーフィズム)などの便利な機能がありません。

私はそうではありませんシングルトンを提唱 。)

3
Jeff Sternal

シングルトンは従来のクラスアプローチを維持し、どこでもstaticキーワードを使用する必要はありません。最初は実装がより難しいかもしれませんが、プログラムのアーキテクチャを大幅に簡素化します。静的クラスとは異なり、パラメータまたはオブジェクトとしてシングルトンを使用できます。

また、他のクラスと同じように、インターフェイスでシングルトンを使用できます。

2
Ed B
  1. シングルトンはインターフェイスを実装し、他のクラスから継承できます
  2. シングルトンは、遅延または非同期で初期化でき、クラスを含むプログラムまたは名前空間がロードされるときに、.NET Framework CLR(共通言語ランタイム)によって自動的にロードされます。静的クラスは通常、最初に読み込まれたときに初期化されますが、クラスローダーの問題が発生する可能性があります。
  3. シングルトンクラスはオブジェクト指向の原則に従います
  4. 静的クラスがスタックに格納されている間、シングルトンオブジェクトはヒープに格納されます。
  5. シングルトンオブジェクトはコンストラクターを持つことができますが、静的クラスは持つことができません。
  6. シングルトンオブジェクトは破棄できますが、静的クラスは破棄できません
  7. シングルトンオブジェクトは静的クラスではなくクローンできます
2
aditya