デザインパターン入門 | Singleton(シングルトン)パターン

「Singleton(シングルトン)」パターンは、「クラスのインスタンスは1つのみしか存在しない」ことを保証したい場合に使えるデザインパターンです。

間違って複数のインスタンスを作ってしまうことを防ぐことができるため、より安全なプログラムを作ることができます。

それでは、「Singleton(シングルトン)」パターンの作り方を見ていきましょう。

「Singleton(シングルトン)」パターンの作り方

今回は、オフィス内のコンピュータを管理する「オフィスコンピュータマネージャ」を例に、「Singleton(シングルトン)」パターンの作り方を学んでいきましょう。

「オフィスコンピュータマネージャ」には、下図のようにオフィス内で利用されている複数のコンピュータの情報が登録されています。

シングルトンイメージ1

しかし、間違って新しい「オフィスコンピュータマネージャ」を複数作ってしまうと、コンピュータの一括管理ができなくなってしまいます。

「オフィスコンピュータマネージャ」のように「必ず1つしかインスタンスが存在してはいけない」という状況で利用できるデザインパターンが「Singleton(シングルトン)」パターンです。

他のデザインパターンと比較すると使いどころも多く使いやすいため、ぜひ使えるようになっていきましょう。

「オフィスコンピュータマネージャ」を表すクラスは次のようになります。

package SampleSingleton;

import java.util.ArrayList;
import java.util.Iterator;

public class OfficeComManager {
	// OfficeComManagerクラスのインスタンスをクラスフィールドで保持
	private static OfficeComManager ocm = new OfficeComManager();
	private static ArrayList coms = new ArrayList();

	// インスタンス化を防止するため、コンストラクタをprivate宣言
	private OfficeComManager() {

	}

	// OfficeComManagerクラスのインスタンスを取得するメソッド
	public static OfficeComManager getInstance() {
		return ocm;
	}

	// コンピュータ登録用メソッド
	public static void addCom(Computer com) {
		coms.add(com);
	}

	// 登録されているコンピュータを表示
	public static void displayComs() {
		Iterator it = coms.iterator();

		while(it.hasNext()) {
			Computer com = (Computer) it.next();
			System.out.println("COM ID:" + com.getId());
			System.out.println("利用者名:" + com.getUserName());
			System.out.println("設置部署:" + com.getDepartment());
			System.out.println("CPU:" + com.getCpu());
			System.out.println("MEMORY:" + com.getMemory() + "GB");
		}
	}
}

private宣言された「ocm」変数に、OfficeComManagerクラスのインスタンスが格納されています。

この変数には外部からアクセスができないため、OfficeComManagerクラスのインスタンスは「getInstance」メソッドから取得します。

間違ってインスタンスを作ってしまう点については、コンストラクタをprivate宣言しているため、インスタンスを作成しようとすると、

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
コンストラクター OfficeComManager() は不可視です

というエラーが発生します。

「コンピュータ」を表すクラスは次のようになります。

package SampleSingleton;

public class Computer {
	private int id;
	private String userName;
	private String department;
	private String cpu;
	private int memory;

	public Computer(int id, String userName, String department, String cpu, int memory) {
		this.id = id;
		this.userName = userName;
		this.department = department;
		this.cpu = cpu;
		this.memory = memory;
	}

	public int getId() {
		return id;
	}

	public String getUserName() {
		return userName;
	}

	public String getDepartment() {
		return department;
	}

	public String getCpu() {
		return cpu;
	}

	public int getMemory() {
		return memory;
	}
}

このクラスのインスタンスは「1台のコンピュータの情報」を保持するため、このインスタンスを「OfficeComManager」に登録を行います。

本当に1つのインスタンスのみが存在しているかを確認するための「main」メソッドは下記のようになります。

package SampleSingleton;

public class Main {

	public static void main(String[] args) {
		System.out.println("■Object IDの確認");
		OfficeComManager ocm1 = OfficeComManager.getInstance();
		//「ocm1」のオブジェクトIDを出力
		System.out.println("ocm1 Object ID:" + java.lang.System.identityHashCode(ocm1));

		OfficeComManager ocm2 = OfficeComManager.getInstance();
		//「ocm2」のオブジェクトIDを出力
		System.out.println("ocm2 Object ID:" + java.lang.System.identityHashCode(ocm2));
		System.out.println("");

		System.out.println("■「ocm1」の登録データを「ocm2」で表示できることを確認");
		//「ocm1」にcomputerを登録
		ocm1.addCom(new Computer(1, "山田 一郎", "営業部", "Intel Core i3-8100 4コア4スレッド", 4));

		//「ocm2」で登録されているコンピュータを表示
		ocm2.displayComs();
	}
}

「main」メソッドの出力結果は下記のようになります。

■Object IDの確認
ocm1 Object ID:118352462
ocm2 Object ID:118352462

■「ocm1」の登録データを「ocm2」で表示できることを確認
COM ID:1
利用者名:山田 一郎
設置部署:営業部
CPU:Intel Core i3-8100 4コア4スレッド
MEMORY:4GB

「ocm1」「ocm2」のそれぞれの変数に「OfficeComManager.getInstance」メソッドで「OfficeComManager」クラスのインスタンスを取得しています。

そして、「java.lang.System.identityHashCode」メソッドを利用してそれぞれの変数内のインスタンスの「オブジェクトID」を表示していますが、「ocm1」「ocm2」も「オブジェクトID」が同値のため、同一のインスタンスだと確認ができます。

次に「ocm1」のインスタンスへ「Computer」クラスのインスタンスを登録しています。

その後、「ocm2」のインスタンスから「displayComs」メソッドを呼び出すと、「ocm1」へ登録したコンピュータの情報が表示されていることから出力情報からも同一の員インスタンスということが確認できました。

実行処理の中で「インスタンスは必ず1つのみ存在している」ことが必要な場合は、「Singleton(シングルトン)」パターンが使えるかどうかを考えていきましょう。

HOMEへ