GOF 23設計モードの一例モード

7705 ワード

シングルデザインモード
コア作用
  • は、クラスが1つのインスタンスのみであることを保証し、そのインスタンスにアクセスするグローバルアクセスポイント
  • を提供する.
    一般的な適用シーン:
  • windowsのタスクマネージャ
  • Webサイトのカウンタ
  • Springでは、各Beanのデフォルトは単一の例の
  • です.
  • 単一モードの利点:
  • は、一例設計モードでは一例しか生成しないため、システム性能のオーバーヘッドを低減することができ、一例のオブジェクトの生成に比較的多くのリソースが必要な場合、例えば構成を読み取り、他の従来のオブジェクトを生成する場合、アプリケーションの起動時に直接一例のオブジェクトを生成し、メモリを永続的に保持することによって
  • を解決することができる.
  • 単例モードは、システムにグローバルなアクセスポイントを設定し、共有リソースアクセスを最適化することができ、例えば、すべてのデータテーブルのマッピング処理を担当する単例クラスを設計することができる.

  • 一般的な5つの単一モードの実装方法:
  • 主:
  • 怠け者式(スレッドは安全で呼び出し効率は高い.ただし、遅延ロードはできない.)
  • 餓漢式(スレッドは安全で呼び出し効率は高くありません.ただし、遅延ロードは可能です.)
  • その他:
  • 二重検出ロック(JVMの下部内部モデルのため、たまに問題が発生します.推奨しません)
  • 静的内部クラス(スレッドが安全で呼び出し効率が高いが、遅延ロード可能)
  • 列挙単例(スレッドが安全で、呼び出し効率が高く、遅延ロードできない)

  • 餓漢式実装(単例オブジェクト即時ロード)
    public class SingletonDemo02{
            private static /*final*/ SingletonDemo02 s = new SingletonDemo02();
            private SingletonDemo02(){} //      
            public static /*synchronized*/ DingletonDemo02 getInstance(){
                return s;
            }
        }
    
    
    public class Client{
        public static void main(String[] args){
            SingletonDemo02 s = SingletonDemo02.getInstance();
            SingletonDemo02 s2 = SingletonDemo02.getInstance();
            System.out.println(s==s2); //   true
        }
    }
  • 餓漢式単例モードコードではstatic変数がクラスマウント時に初期化され、この場合も複数のスレッドオブジェクトがそのオブジェクトにアクセスする問題はありません.仮想マシンは、クラスが一度だけマウントされることを保証し、同時アクセスの問題は発生しません.したがって、synchronizedのキーワード
  • を省略することができる.
  • 問題:getInstance()を呼び出すのではなく、クラスをロードするだけで、呼び出されない場合は、リソースの浪費になります.

  • 怠け者実装(単一オブジェクト遅延ロード)
    public class SingletonDemo02{
        private static SingletonDemo02 s;
    
        private SingletonDemo01(){} //      
    
        public static synchronized SingletonDemo02 getInstance(){
            if(s==null){
                s = new SingletonDemo02();
            }
            return s;
        }
    }
  • 要点:
  • lazy load! 遅延ロード、怠け者ロード!本当に使う時やっとロードします!

  • 質問:
  • リソースの使用率が高くなりました.しかし,getInstance()メソッドを呼び出すたびに同期し,同時効率は低い.


  • デュアル検出ロック実装
    public class SingletonDemo03{
        private static SingeltonDemo03 instance = null;
        public static SingeltonDemo03 getInstance(){
            if(instance == null){
                SingletonDemo03 sc;
                synchronized(SingletonDemo03.class){
                    sc = instance;
                    if(sc == null){
                        synchronized(SingletonDemo03.class){
                            if(sc == null){
                                sc = new SingletonDemo03();
                            }
                        }
                        instance = sc;
                    }
                }
            }
            reutrn instance;
        }
        private SingletonDemo03(){
        }
    }
  • このモードは、同期コンテンツをif内部に送信し、実行の効率を向上させ、オブジェクトを取得するたびに同期する必要がなく、同期が作成されたのは初めてで、以降は必要ありません.
  • 質問:
  • コンパイラの最適化の理由とJVMの最下位の内部モデルのため、たまに問題が発生します.
  • は推奨されません.

    静的内部クラス実装方式(怠け者ロード方式でもある)
    public class SingletonDemo04{
        private static class SingletonClassInstance{
            private static final SingletonDemo04 instance = new SingletonDemo04();
        }
        public static SingletonDemo04 getInstance(){
            return SingletonClassInstance.instance;
        }
        private SingletonDemo04(){
        }
    }
  • 要点:
  • 外部クラスにstatic属性がなければ、餓漢式のように直ちにオブジェクト
  • をロードすることはない.
  • 静的内部クラスは、getInstance()が実際に呼び出されている場合にのみロードされます.クラスをロードするときはスレッドが安全です.Instanceはstatic finalタイプで、メモリにこのようなインスタンスが1つしか存在しないことを保証し、1回しか値を割り当てることができず、スレッドのセキュリティを保証します.
  • は、同時効率性と遅延負荷の利点を兼ね備えています.


  • 単一例モードを列挙で実現する
    public enum SingletonDemo05{
        /**
        *          ,     Singleton     
        **/
        INSTANCE;
        /**
        *           
        **/
        public static void singletonOperation(){
            //    
        }
    }
    
    public static void mian(String[] args){
        SingletonDemo05 sd = SingletonDemo05.INSTANCE;
        SingletonDemo05 sd2 = SingletonDemo05.INSTANCE;
        System.out.println(sd==sd2);
    }
  • の利点:
  • 単純
  • を実現
  • 列挙自体が単一のパターンである.JVMによって根本的に保障されています!反射と逆シーケンス化による脆弱性を回避!
  • 無遅延記載

  • どのように選択しますか?
  • 単一のオブジェクトは、リソースの使用量が少なく、遅延ロードを必要としません.
  • 列挙式は餓漢式
  • より良い
  • 単例オブジェクトはリソースを占有し、遅延ロードが必要である
  • 静的内部クラスは怠け者式
  • より良い

    単例モードの解読を防止する(列挙実装を含まない)
  • 反射による単一モードの解読
  • は、構成方法において異常
  • を手動で放出することができる.
  • 逆シーケンス化により単一例モードを解読する
  • は、readResolve()を定義することによって、異なるオブジェクトの獲得を防止することができ、(実際にはコールバック)、どのオブジェクトを返すかを定義することができる.