前回はマルチスレッドを使って複数の処理を同時に動かす方法を学びました。
今回は「デザインパターン」について解説します。 デザインパターンとは、プログラムを設計するときによく登場する問題に対して、先人たちが考えた再利用可能な解決策のことです。今回はその中でも特によく使われる「Singleton(シングルトン)」と「Factory(ファクトリー)」の2つを紹介します。
デザインパターンとは
デザインパターンは、オブジェクト指向プログラミングにおける典型的な設計の問題を解決するための「定石」です。1994年に「GoF(Gang of Four)」と呼ばれる4人の著者がまとめた23種類のパターンが有名で、現在も広く使われています。
パターンを覚えることで、「こういう場面ではこう設計すればよい」という判断が素早くでき、チームでの開発でも共通の言葉として使えるようになります。
Singletonパターン
Singletonパターンは、「あるクラスのインスタンスをプログラム全体で必ず1つだけに制限する」パターンです。たとえば、アプリ全体で共有する設定情報やログ管理など、複数のインスタンスが存在すると困る場面で使われます。
ポイントは以下の3つです。
- コンストラクタを
privateにして外部からのnewを禁止する - 唯一のインスタンスをクラス内で
staticフィールドとして保持する getInstance()メソッドでそのインスタンスを返す
サンプルコード(Singleton)
ファイル作成
「Java08」フォルダに AppConfig.java、SingletonTest.java という名前でファイルを作成します

コード入力
AppConfig.java に以下のコードを入力します。
public class AppConfig {
private static AppConfig instance;
private String appName;
private AppConfig() {
appName = "ぱんまるアプリ";
}
public static AppConfig getInstance() {
if (instance == null) {
instance = new AppConfig();
}
return instance;
}
public String getAppName() {
return appName;
}
}

SingletonTest.java に以下のコードを入力します。
public class SingletonTest {
public static void main(String[] args) {
AppConfig config1 = AppConfig.getInstance();
AppConfig config2 = AppConfig.getInstance();
System.out.println(config1.getAppName());
System.out.println(config2.getAppName());
System.out.println("同じインスタンス?:" + (config1 == config2));
}
}

コンパイル
javac AppConfig.java SingletonTest.java

実行
java SingletonTest
実行結果は次のようになります。
ぱんまるアプリ
ぱんまるアプリ
同じインスタンス?:true

Factoryパターン
Factoryパターンは、「インスタンスの生成をまとめて管理する」パターンです。new をあちこちに書く代わりに、専用の「ファクトリークラス」にインスタンス生成の処理をまとめることで、種類が増えたときの修正箇所を1か所に絞ることができます。
以前学んだインターフェースとポリモーフィズムと組み合わせることで、より効果を発揮します。
サンプルコード(Factory)
ファイル作成
「Java08」フォルダに Drink.java、Coffee.java、Tea.java、DrinkFactory.java、FactoryTest.java という名前でファイルを作成します

コード入力
Drink.java に以下のコードを入力します。
public interface Drink {
void serve();
}

Coffee.java に以下のコードを入力します。
public class Coffee implements Drink {
@Override
public void serve() {
System.out.println("コーヒーをお出しします");
}
}

Tea.java に以下のコードを入力します。
public class Tea implements Drink {
@Override
public void serve() {
System.out.println("お茶をお出しします");
}
}

DrinkFactory.java に以下のコードを入力します。
public class DrinkFactory {
public static Drink create(String type) {
switch (type) {
case "coffee":
return new Coffee();
case "tea":
return new Tea();
default:
System.out.println("不明な種類です:" + type);
return null;
}
}
}

FactoryTest.java に以下のコードを入力します。
public class FactoryTest {
public static void main(String[] args) {
Drink drink1 = DrinkFactory.create("coffee");
Drink drink2 = DrinkFactory.create("tea");
Drink drink3 = DrinkFactory.create("juice");
if (drink1 != null) drink1.serve();
if (drink2 != null) drink2.serve();
if (drink3 != null) drink3.serve();
}
}

コンパイル
javac Drink.java Coffee.java Tea.java DrinkFactory.java FactoryTest.java

実行
java FactoryTest
実行結果は次のようになります。
不明な種類です:juice
コーヒーをお出しします
お茶をお出しします

コードの解説
Singletonパターンでは、AppConfig のコンストラクタを private にすることで、外部から new AppConfig() とすることができなくなっています。代わりに getInstance() メソッドを通じてのみインスタンスを取得できます。getInstance() の中では、instance が null(まだインスタンスが作られていない)のときだけ new を行い、2回目以降は最初に作ったインスタンスをそのまま返します。config1 == config2 が true になっているのは、2つの変数が同じインスタンスを指しているためです。
Factoryパターンでは、DrinkFactory.create("coffee") のように文字列を渡すだけで適切なインスタンスが返ってきます。呼び出す側は Coffee や Tea クラスの存在を意識する必要がなく、新しい種類の飲み物を追加したい場合は DrinkFactory にcaseを追加するだけで済みます。戻り値の型を Drink インターフェースにしているため、呼び出し側ではどの種類でも serve() を呼び出せます。以前学んだインターフェースとポリモーフィズムが活きている部分です。
まとめ
Singletonパターンはインスタンスをプログラム全体で1つに制限したい場面で、Factoryパターンはインスタンス生成の処理を1か所にまとめたい場面で使われます。どちらも「こういう設計にすれば、こういう問題が解決できる」という共通の考え方であり、コードの見通しがよくなるだけでなく、チームでの会話でも「Singletonで実装した」と伝えるだけで意図が伝わるという利点があります。デザインパターンはほかにも多くの種類がありますので、興味を持った方はぜひさらに調べてみてください。
2026/06/28(日) ぱんまる


コメント