静的クラスの代わりにシングルトン パターンを使用する必要があるのはどのような場合ですか?[閉まっている]

StackOverflow https://stackoverflow.com/questions/46541

  •  09-06-2019
  •  | 
  •  

質問

を使用するかどうかを決定する際の設計上の考慮事項を挙げてください。 シングルトン 静的クラスとの比較。これを行うと、この 2 つを対比する必要が生じるため、思いつく限りの対比は、思考プロセスを示すのにも役立ちます。また、面接官は皆、具体的な例を見ることを好みます。:)

役に立ちましたか?

解決

  • シングルトンはインターフェイスを実装し、他のクラスから継承できます。
  • シングルトンは遅延ロードできます。実際に必要な場合のみ。これは、初期化に高価なリソースの読み込みやデータベース接続が含まれる場合に非常に便利です。
  • シングルトンは実際のオブジェクトを提供します。
  • シングルトンはファクトリに拡張できます。舞台裏でのオブジェクト管理は抽象的なため、保守性が向上し、より良いコードが得られます。

他のヒント

「両方を避ける」のはどうでしょうか?シングルトンと静的クラス:

  • グローバル状態を導入する可能性がある
  • 他の複数のクラスと緊密に結合する
  • 依存関係を非表示にする
  • クラスを単独で単体テストすることが困難になる可能性がある

代わりに調べてください 依存関係の注入 そして コントロールコンテナの反転 図書館。IoC ライブラリのいくつかは、有効期間管理を処理します。

(いつものように、静的数学クラスや C# 拡張メソッドなどの例外はあります。)

唯一の違いは構文だと思います。MySingleton.Current.Whatever() と MySingleton.Whatever()。デビッドが述べたように、どちらの場合でも、状態は最終的には「静的」です。


編集:埋葬旅団が掘削地からやって来ました...とにかく、シングルトンが必要なケースを考えました。静的クラスは基本クラスから継承したり、インターフェイスを実装したりすることはできません (少なくとも .Net ではできません)。したがって、この機能が必要な場合は、シングルトンを使用する必要があります。

この問題に関する私のお気に入りの議論の 1 つは、 ここ (元のサイトはダウンしているため、現在はリンクされています インターネット アーカイブ ウェイバック マシン.)

シングルトンの柔軟性の利点を要約すると、次のようになります。

  • シングルトンは工場に簡単に変換できます
  • シングルトンは、さまざまなサブクラスを返すように簡単に変更できます
  • これにより、アプリケーションがより保守しやすくなる可能性があります

静的変数をロードした静的クラスは、ちょっとしたハックです。

/**
 * Grotty static semaphore
 **/
 public static class Ugly {

   private static int count;

   public synchronized static void increment(){
        count++;
   }

   public synchronized static void decrement(){
        count--;
        if( count<0 ) {
            count=0;
        }
   }

   public synchronized static boolean isClear(){
         return count==0;    

    }
   }

実際のインスタンスを含むシングルトンの方が優れています。

/**
 * Grotty static semaphore
 **/
 public static class LessUgly {
   private static LessUgly instance;

   private int count;

   private LessUgly(){
   }

   public static synchronized getInstance(){
     if( instance==null){
        instance = new LessUgly();
     }
     return instance;
   }
   public synchronized void increment(){
        count++;
   }

   public synchronized void decrement(){
        count--;
        if( count<0 ) {
            count=0;
        }
   }

   public synchronized boolean isClear(){
         return count==0;    

    }
   }

状態はインスタンス内のみにあります。

したがって、シングルトンは後でプーリングやスレッドローカルインスタンスなどを行うように変更できます。また、利点を得るために、すでに記述されたコードを変更する必要はありません。

public static class LessUgly {
       private static Hashtable<String,LessUgly> session;
       private static FIFO<LessUgly> freePool = new FIFO<LessUgly>();
       private static final POOL_SIZE=5;
       private int count;

       private LessUgly(){
       }

       public static synchronized getInstance(){
         if( session==null){
            session = new Hashtable<String,LessUgly>(POOL_SIZE);
            for( int i=0; i < POOL_SIZE; i++){
               LessUgly instance = new LessUgly();  
               freePool.add( instance)
            }
         }
         LessUgly instance = session.get( Session.getSessionID());
         if( instance == null){
            instance = freePool.read();
         }
         if( instance==null){
             // TODO search sessions for expired ones. Return spares to the freePool. 
             //FIXME took too long to write example in blog editor.
         }
         return instance;
       }     

静的クラスを使用して同様のことを行うことは可能ですが、間接ディスパッチでは呼び出しごとのオーバーヘッドが発生します。

インスタンスを取得し、引数として関数に渡すことができます。これにより、コードが「正しい」シングルトンに送信されるようになります。必要なのは 1 つだけであることはわかっています...そうしないまでは。

大きな利点は、ステートフル シングルトンをスレッド セーフにできるのに対し、静的クラスはシークレット シングルトンに変更しない限りスレッド セーフにできないことです。

シングルトンをサービスのようなものと考えてください。これは、特定の機能セットを提供するオブジェクトです。例えば。

ObjectFactory.getInstance().makeObject();

オブジェクト ファクトリは、特定のサービスを実行するオブジェクトです。

対照的に、静的メソッドが満載されたクラスは、実行する可能性のあるアクションのコレクションであり、関連するグループ (クラス) に編成されています。例えば。

StringUtils.reverseString("Hello");
StringUtils.concat("Hello", "World");

ここでの StringUtils の例は、どこにでも適用できる機能のコレクションです。シングルトン ファクトリ オブジェクトは、必要に応じて作成して渡すことができる、明確な責任を持つ特定のタイプのオブジェクトです。

静的クラスは実行時にインスタンス化されます。これには時間がかかる場合があります。シングルトンは必要な場合にのみインスタンス化できます。

シングルトンは静的クラスと同じように使用しないでください。要するに、

MyStaticClass.GetInstance().DoSomething();

本質的にはと同じです

MyStaticClass.DoSomething();

実際にやるべきことは、 シングルトンを単なる別のオブジェクトとして扱う. 。サービスがシングルトン タイプのインスタンスを必要とする場合は、そのインスタンスをコンストラクターに渡します。

var svc = new MyComplexServce(MyStaticClass.GetInstance());

サービスはオブジェクトがシングルトンであることを認識すべきではなく、オブジェクトを単なるオブジェクトとして扱う必要があります。

このオブジェクトは、実装の詳細として、また全体的な構成の一部として、作業を容易にする場合にはシングルトンとして実装できます。しかし、オブジェクトを使用するものは、そのオブジェクトがシングルトンであるかどうかを知る必要はありません。

「静的クラス」が静的変数のみを持つクラスを意味する場合、それらは実際に状態を維持できます。私の理解では、唯一の違いは、これにアクセスする方法だけです。例えば:

MySingleton().getInstance().doSomething();

MySingleton.doSomething();

MySingleton の内部は明らかに両者で異なりますが、スレッド セーフティの問題を除けば、クライアント コードに関してはどちらも同じように実行されます。

シングルトン パターンは通常、複数のスレッドが同時にデータにアクセスできる、インスタンスに依存しないデータまたは静的データをサービスするために使用されます。一例として、州コードが挙げられます。

シングルトンは決して使用しないでください (変更可能な状態を持たないクラスをシングルトンと見なさない限り)。「静的クラス」には、おそらくスレッドセーフなキャッシュなどを除いて、変更可能な状態があってはなりません。

シングルトンのほとんどの例は、それを行わない方法を示しています。

シングルトンが、その後クリーンアップするために処分できるものである場合、それが限られたリソースである場合に考慮できます。そのうちの 1 つだけ)常に必要なわけではなく、割り当てられるときに何らかのメモリまたはリソースのコストがかかります。

静的状態フィールドを含む静的クラスとは対照的に、シングルトンがある場合のクリーンアップ コードはより自然に見えます。

ただし、コードはどちらの方法でも同じように見えるため、質問するより具体的な理由がある場合は、おそらく詳しく説明する必要があります。

この 2 つは非常に似ている可能性がありますが、真のシングルトンは次のとおりである必要があることに注意してください。 自体 インスタンス化されて (一度付与されて)、提供されます。のインスタンスを返す PHP データベース クラス mysqli インスタンスを静的メンバーとして持つクラスのインスタンスではなく、別のクラスのインスタンスを返すため、実際にはシングルトン (と呼ぶ人もいます) ではありません。

したがって、コード内でインスタンスを 1 つだけ許可する新しいクラスを作成する場合は、それをシングルトンとして作成した方がよいでしょう。これは、プレーン ジェーン クラスを作成し、単一インスタンス化の要件を容易にするためにそれに追加するものと考えてください。変更できない他の人のクラスを使用している場合 (例: mysqli)、静的クラスを使用する必要があります (たとえその定義にキーワードをプレフィックスとして付けなかったとしても)。

シングルトンはより柔軟であり、Instance メソッドが何らかのコンテキストに基づいてシングルトンの型のさまざまな具体的なサブクラスを返すようにする場合に便利です。

静的クラスを引数として渡すことはできません。シングルトンのインスタンスは可能です。他の回答で述べたように、静的クラスのスレッドの問題に注意してください。

RP

シングルトンにはコンストラクターとデストラクターがある場合があります。言語によっては、シングルトンが初めて使用されるときにコンストラクターが自動的に呼び出される場合もあれば、シングルトンがまったく使用されない場合にはコンストラクターが呼び出されない場合もあります。静的クラスにはそのような自動初期化はありません。

シングルトン オブジェクトへの参照を取得すると、他のオブジェクトと同様に使用できます。シングルトンへの参照が以前に保存されている場合、クライアント コードはシングルトンを使用していることを認識する必要さえない場合があります。

Foo foo = Foo.getInstance();
doSomeWork(foo); // doSomeWork wont even know Foo is a singleton

これにより、シングルトン パターンを廃止して IoC などの実際のパターンを選択する場合、明らかに作業が簡単になります。

ルックアップ テーブルなど、可能であればコンパイル時に計算するものを実行時に計算する必要がある場合は、シングルトン パターンを使用します。

シングルトンが静的クラスよりも意味があるのは、高価なリソース (データベース接続など) のプールを構築する必要がある場合だと思います。誰もプールを使用しない場合は、プールを作成する必要はありません (静的クラスは、クラスがロードされるときにコストのかかる作業を行うことを意味します)。

データの効率的なキャッシュを強制したい場合は、シングルトンも良いアイデアです。たとえば、XML ドキュメント内の定義を検索するクラスがあります。ドキュメントの解析には時間がかかるため、定義のキャッシュを設定しました (outOfmemeoryErrors を避けるために SoftReferences を使用しています)。必要な定義がキャッシュにない場合は、高価な XML 解析を実行します。それ以外の場合は、キャッシュからコピーを返します。複数のキャッシュがあると、同じ定義を複数回ロードする必要がある可能性があるため、静的キャッシュが必要になります。通常の (非静的) データ メンバーのみを使用してクラスを作成できるように、このクラスをシングルトンとして実装することにしました。これにより、何らかの理由 (シリアル化、単体テストなど) でクラスが必要になった場合でも、クラスのインスタンスを作成できます。

すでに述べたように、シングルトンはサービスのようなものです。プロはその柔軟性です。静的、そうですね、シングルトンを実装するにはいくつかの静的部分が必要です。

Singleton には、実際のオブジェクトのインスタンス化を処理するコードがあり、競合の問題が発生した場合に非常に役立ちます。静的ソリューションでは、複数のコードの場所で競合の問題に対処する必要がある場合があります。

ただし、いくつかの静的変数を使用してシングルトンを構築できるのと同じように、「goto」と比較できる場合があります。他の構造物を構築するのに非常に便利ですが、実際には使い方を知る必要があり、「使いすぎ」ないようにしてください。したがって、一般的にはシングルトンを使用し、必要に応じて静的を使用することをお勧めします。

他の投稿もチェックしてください: シングルトン実装ではなく静的クラスを選択する理由は何ですか?

参照する これ

まとめ:

a.従うことができる簡単な経験則の 1 つは、状態を維持する必要がない場合は静的クラスを使用でき、そうでない場合はシングルトンを使用する必要があります。

b.特に「重い」オブジェクトの場合は、シングルトンを使用します。オブジェクトが大きく、適切な量のメモリを占有する場合、多数の n/w 呼び出し (接続プール) などが発生します。複数回インスタンス化されないようにするため。シングルトン クラスは、そのようなケースが起こらないようにするのに役立ちます

単一クラスに状態が必要な場合。シングルトンはグローバル状態を維持しますが、静的クラスはそうではありません。

たとえば、レジ​​ストリ クラスの周りにヘルパーを作成します。変更可能なハイブがある場合 (HKey Current User とHKEY ローカル マシン)、次のようにすることができます。

RegistryEditor editor = RegistryEditor.GetInstance();
editor.Hive = LocalMachine

これで、そのシングルトンへのさらなる呼び出しはローカル マシン ハイブ上で動作するようになります。それ以外の場合は、静的クラスを使用して、ローカル マシン ハイブを毎回指定するか、次のようなメソッドを使用する必要があります。 ReadSubkeyFromLocalMachine.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top