Menu
Coddy logo textTech

シングルトンパターン

CoddyのJavaジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 65/87。

Singleton Pattern(シングルトンパターン)は、アプリケーション全体でクラスのインスタンスが1つだけであることを保証し、そのインスタンスへのグローバルなアクセスポイントを提供する生成に関するデザインパターンです。これは、設定マネージャー、コネクションプール、ロギングサービスのように、共有すべきリソースに役立ちます。

このパターンは、コンストラクタをprivateにして直接のインスタンス化を防ぐことで機能します。代わりに、静的メソッドが唯一のインスタンスへのアクセスを制御します。

public class DatabaseConnection {
    private static DatabaseConnection instance;
    
    // プライベートコンストラクタにより、直接のインスタンス化を防ぎます
    private DatabaseConnection() {
        System.out.println("Connection created");
    }
    
    // グローバルアクセスポイント
    public static DatabaseConnection getInstance() {
        if (instance == null) {
            instance = new DatabaseConnection();
        }
        return instance;
    }
    
    public void query(String sql) {
        System.out.println("Executing: " + sql);
    }
}

getInstance() を呼び出すたびに、同じオブジェクトが返されます。インスタンスは最初にリクエストされたときにのみ作成されます。これは遅延初期化(lazy initialization)と呼ばれます:

DatabaseConnection db1 = DatabaseConnection.getInstance();
DatabaseConnection db2 = DatabaseConnection.getInstance();

System.out.println(db1 == db2);  // true - 同一のインスタンス

Singletonの主要な構成要素は次のとおりです:インスタンスを保持するprivate staticフィールド、privateコンストラクタ、そしてインスタンスを返すpublic staticメソッドです。この組み合わせにより、オブジェクトを何度リクエストしても、常に同じオブジェクトが返されることが保証されます。

challenge icon

チャレンジ

簡単

シングルトンパターンを使用して、アプリケーションの構成マネージャーを構築しましょう!構成マネージャーは、アプリケーションのすべての部分が、何度アクセスを要求しても同じ設定を共有することを保証します。

コードは2つのファイルに分けて構成します:

  • AppConfig.java: アプリケーションの構成設定を管理するシングルトンクラスを作成します。AppConfig には以下を含める必要があります:

    単一のインスタンスを保持するための private static フィールド。

    appName という名前の private String フィールドと、maxUsers という名前の private int フィールド。

    appName"MyApplication" に、maxUsers100 に初期化し、AppConfig initialized と出力する private コンストラクタ。

    インスタンスがまだ存在しない場合にのみ作成し(遅延初期化)、それを返す public static な getInstance() メソッド。

    アプリ名を更新する setAppName(String name) メソッド。

    最大ユーザー数を更新する setMaxUsers(int max) メソッド。

    App: [appName], Max Users: [maxUsers] と出力する displaySettings() メソッド。

  • Main.java: シングルトンが正しく動作することを実証してください!新しいアプリ名(String)と新しい最大ユーザー数(integer)の2つの入力を受け取ります。

    まず、AppConfig のインスタンスを取得し、config1 という変数に格納します。displaySettings() を呼び出してデフォルト値を表示します。

    次に、config1 に対して setAppNamesetMaxUsers を呼び出し、入力値を使用して設定を更新します。

    別のインスタンスを取得して config2 に格納します。config2displaySettings() を呼び出し、config1 を通じて行われた変更が反映されていることを証明します。

    最後に、config1 == config2 を比較して、両方の参照が同じオブジェクトを指しているかどうかを Same instance: [true/false] の形式で出力します。

入力は、新しいアプリ名(String)、新しい最大ユーザー数(integer)の順に2つ受け取ります。

このチャレンジは、シングルトンパターンの核心的な利点を示しています。構成を何度要求しても、常に同じ共有状態を持つ同じインスタンスを取得できるのです!

チートシート

シングルトンパターン(Singleton Pattern)は、アプリケーション全体でクラスのインスタンスが1つだけであることを保証し、そのインスタンスへのグローバルなアクセスポイントを提供します。

主な構成要素:

  • 唯一のインスタンスを保持する private static フィールド
  • 直接のインスタンス化を防ぐための private コンストラクタ
  • インスタンスを返す public static メソッド

基本的な実装:

public class DatabaseConnection {
    private static DatabaseConnection instance;
    
    // プライベートコンストラクタにより、直接のインスタンス化を防ぎます
    private DatabaseConnection() {
        System.out.println("Connection created");
    }
    
    // グローバルアクセスポイント
    public static DatabaseConnection getInstance() {
        if (instance == null) {
            instance = new DatabaseConnection();
        }
        return instance;
    }
    
    public void query(String sql) {
        System.out.println("Executing: " + sql);
    }
}

使用例:

DatabaseConnection db1 = DatabaseConnection.getInstance();
DatabaseConnection db2 = DatabaseConnection.getInstance();

System.out.println(db1 == db2);  // true - 同じインスタンス

インスタンスは最初にリクエストされたときにのみ作成されます。これは遅延初期化(lazy initialization)と呼ばれます。getInstance() を呼び出すたびに同じオブジェクトが返されるため、アプリケーション全体で状態が共有されることが保証されます。

自分で試してみよう

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // 入力を読み込む
        String newAppName = scanner.nextLine();
        int newMaxUsers = scanner.nextInt();
        
        // TODO: AppConfig の最初のインスタンスを取得し、config1 に格納する
        
        // TODO: config1 で displaySettings() を呼び出し、デフォルト値を表示する
        
        // TODO: config1 の setAppName と setMaxUsers を使用して設定を更新する
        
        // TODO: 別のインスタンスを取得し、config2 に格納する
        
        // TODO: config2 で displaySettings() を呼び出し、変更が共有されていることを証明する
        
        // TODO: 両方の参照が同じオブジェクトを指しているかを出力する:
        // config1 == config2 を使用して "Same instance: [true/false]" と出力する
    }
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン