CodeGym /Java Blog /ランダム /Java のパターンとシングルトン
John Squirrels
レベル 41
San Francisco

Java のパターンとシングルトン

ランダム グループに公開済み
この記事は、デザイン パターンの概念に初めて遭遇した人、シングルトンという用語を聞いたことがある人、または何らかの形でシングルトン パターンを実装したものの、何が起こっているのか理解できなかった人を対象としています。いらっしゃいませ!CodeGym の学生は、レベル 15 で初めて設計パターンに遭遇します。そのとき、キャプテンは予期せず、Java シングルトン パターンを遅延実装で実装することで理解を「強化」するように求めました。シングルトンパターンについて初めて聞いた学生は、すぐに多くの質問をします。デザイン パターンとは一体何ですか? なぜそれが必要なのでしょうか? シングルトンとは何ですか? 最後に、遅延実装とは何ですか? これらの質問に順番に答えてみましょう。

デザインパターンとは一体何でしょうか?

この質問に最もよく理解して答えるためには、少し歴史を知ることが必要だと思います。興味深いアイデアを思いついた 4 人の有名なプログラミング作者 (Erich Gamma、John Vlissides、Ralph Johnson、Richard Helm) がいます。彼らは、ソフトウェア開発では、ほぼ同じ問題を解決し、同じ方法で構造化されたコードを書くことが必要になることが多いことに気づきました。そこで彼らは、オブジェクト指向プログラミングで頻繁に使用する必要がある典型的なパターンを説明することにしました。彼らの本は、「Design Patterns: Elements of Reusable Object-Oriented Software」というタイトルで 1994 年に出版されました。この本の名前が長すぎることが判明し、人々はそれを単にギャング・オブ・フォーの本と呼ぶようになりました。初版には23柄が収録されていました。その後、他にも数十のパターンが発見されました。
デザイン パターンは、一般的な問題に対する標準化された解決策です。
シングルトンパターンそのうちの 1 つにすぎません。

なぜデザインパターンが必要なのでしょうか?

パターンを知らなくてもプログラミングはできます。結局のところ、レベル 15 までに、その存在さえ知らずに CodeGym で何百ものミニプログラムをすでに書いていることになります。これは、デザイン パターンが、その使い方によって熟練者とアマチュアを区別する一種のツールであることを示唆しています。デザイン パターンは、典型的な問題を適切に解決する方法を記述します。これは、パターンを知ることで時間を節約できることを意味します。その意味では、それらはアルゴリズムに似ています。たとえば、 ブラックジャックと数字を使用して独自の並べ替えアルゴリズムを作成できます。それには多くの時間を費やすか、長い間理解され説明されてきたものを実装することもできます。デザインパターンも同様です。さらに、デザイン パターンを使用すると、コードがより標準になり、パターンによくある落とし穴がずっと前に特定され、排除されているため、適切なパターンを使用すると間違いを犯す可能性が低くなります。何よりも、パターンの知識は、プログラマーがお互いをよりよく理解するのに役立ちます。他のプログラマに長々と説明する代わりに、パターンの名前を言うだけで済みます。要約すると、デザイン パターンは次のことに役立ちます。
  • 車輪の再発明ではなく、代わりに標準的なソリューションを使用します。
  • コードを標準化する。
  • 用語を標準化する。
このセクションの結論として、デザイン パターン全体が 3 つの大きなグループに分類できることに注意してください。 パターンとシングルトン - 初めて触れるすべての人へ - 2

最後にシングルトンパターン

シングルトンは作成パターンです。このパターンでは、クラスのインスタンスが 1 つだけ存在することが保証され、このオブジェクトにグローバル アクセス ポイントが提供されます。説明から、このパターンは次の 2 つの場合に適用されることが明らかです。
  1. プログラムで特定のクラスのオブジェクトを 1 つだけ作成する必要がある場合。たとえば、コンピュータ ゲームには、Hero クラスと、ゲーム内の唯一のヒーローを記述する Hero オブジェクトが 1 つだけある場合があります。

  2. オブジェクトへのグローバル アクセスのためのポイントを提供する必要がある場合。つまり、プログラム内のどこからでもオブジェクトを利用できるようにする必要があります。残念ながら、グローバル変数は書き込み保護されていないため、単に作成するだけでは十分ではありません。誰でも変数の値を変更できるため、オブジェクトのグローバル アクセス ポイントが失われる可能性があります。シングルトンのこれらのプロパティは、たとえば、データベースと連携するオブジェクトがあり、プログラムのさまざまな部分からデータベースにアクセスする必要がある場合に必要です。シングルトンは、以前に作成されたインスタンスを置き換えるコードを誰も書かないようにします。
したがって、シングルトンは、プログラム内に特定の種類のオブジェクトが 1 つだけ存在する必要があること、およびそのオブジェクトへのグローバル アクセスが必要であるという 2 つのニーズを満たしていました。レベル 15 の例では、キャプテンは次のタスクにこのパターンを実装するように求めています。
  1. 遅延初期化を使用したシングルトンの例を見つけてください。

  2. 同じ原理を使用して、3 つのシングルトン クラス (Sun、Moon、Earth) を別々のファイルに作成します。

  3. 埋め込むSunMoonEarthクラスのインターフェイス。

  4. Solutionクラスの静的ブロックで、readKeyFromConsoleAndInitPlanet方法。

  5. を実装します。readKeyFromConsoleAndInitPlanetメソッドの機能:

    • 5.1. コンソールから1 つの文字列パラメータを読み取ります

    • 5.2. パラメータが次のいずれかに等しい場合、インターフェイスの定数を使用して、適切なthePlanetオブジェクトを作成します。

タスク条件を注意深く読むと、ここでシングルトンが必要な理由が明確にわかります。実際、 SunMoonEarthの各クラスのインスタンスを作成するように求められます。太陽、月、地球は 1 つだけ作成すべきであると仮定するのは理にかなっています。そうしないと、もちろんあなたが自分のバージョンのスター・ウォーズを書いている場合を除き、不条理な状況に陥ります。3 つのステップによる Java でのシングルトンパターンの実装Java では、コンストラクターは常に新しいオブジェクトを返すため、通常のコンストラクターを使用してシングルトンの動作を実装することはできません。したがって、シングルトンのすべての実装は、要約すると、コンストラクターを非表示にし、シングルトン オブジェクトの有効期間を制御するパブリック静的メソッドを作成し、新しく出現したオブジェクトをすべて「破棄」します。シングルトンにアクセスすると、新しいオブジェクトを作成するか (プログラムにオブジェクトがまだ存在しない場合)、既存のオブジェクトを返す必要があります。これを達成するには:
  1. 単一のオブジェクトを格納するプライベート静的フィールドをクラスに与える必要があります。

    
    public class LazyInitializedSingleton {
    	private static LazyInitializedSingleton instance; // #1
    }
    
  2. (デフォルト) コンストラクターをプライベートにします。これは、クラスの外部からアクセスできず、新しいオブジェクトを返すことができないことを意味します。

    
    public class LazyInitializedSingleton {
    	private static LazyInitializedSingleton instance;
    private LazyInitializedSingleton(){} // #2
    } 
    
  3. シングルトンを取得するために使用される静的作成メソッドを宣言します。

    
    public class LazyInitializedSingleton {
        private static LazyInitializedSingleton instance;
            private LazyInitializedSingleton() {}
            public static LazyInitializedSingleton getInstance() { // #3
            if (instance == null) { // If the object has not yet been created
                instance = new LazyInitializedSingleton(); // Create a new object
            }
            return instance; // Return the previously created object
        }
    }
    
上記の例は、単にコンストラクターを非表示にし、標準のコンストラクターの代わりに独自のメソッドを提供しているだけなので、やや不格好です。この記事は、CodeGym の学生がこのパターン (および一般的なデザイン パターン) に触れることを目的としているため、より複雑なシングルトン実装の微妙な違いについてはここでは説明しません。プログラムの複雑さに応じて、このパターンをさらに改良する必要がある可能性があることにだけ注意してください。たとえば、マルチスレッド環境 (スレッドに関する記事を参照) では、複数の異なるスレッドがシングルトン メソッドに同時にアクセスする可能性があり、それぞれのスレッドがクラスのインスタンスを作成する可能性があるため、上記のコードは動作しなくなります。その結果、適切なスレッドセーフなシングルトンを作成するには、依然としていくつかの異なるアプローチが存在します。しかし、それはまた別の話です =)

そして最後に... 船長が尋ねたこの怠惰な初期化とは何ですか?

遅延初期化は遅延初期化とも呼ばれます。これは、リソースを大量に消費する操作 (オブジェクトの作成はリソースを大量に消費する操作) を、事前ではなくオンデマンドで実行するプログラミングのトリックです。では、シングルトンJava コードでは実際に何が起こっているのでしょうか? つまり、オブジェクトは事前ではなく、アクセスされたときに作成されます。遅延初期化がシングルトンパターンに何らかの形で厳密に結び付けられていると想定すべきではありません。遅延初期化は、プロキシやファクトリー メソッドなどの他の創造的なデザイン パターンでも使用されますが、これもまた別の話です =)
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION