1.

staticクラスとシングルトンの違い

編集

本稿ではstaticクラスとシングルトンの違いを説明します。どちらも「インスタンスが事実上1つしかない」状態を作るパターンですが、設計上の性質や扱いやすさに違いがあります。

※随時追加予定

本質的な違い

項目staticクラスシングルトン
インスタンス持たない(メンバはすべてstatic)1つだけ持つ(インスタンス取得用メソッド経由)
状態保持静的フィールドインスタンスフィールド
引数として渡す不可(クラス自体は渡せない)可能(オブジェクトとして扱える)
インターフェース実装不可(staticメソッドはインターフェース要件を満たせない)可能
継承・オーバーライド不可可能
遅延初期化クラスロード時に固定初回 getInstance() で生成可能
テスト容易性差し替え不可、モック困難DI(依存注入)で差し替え可能
マルチインスタンス化不可(1つの状態)設計上は1つだが、必要なら派生で複数可

シングルトンの利点(記事原文に基づく)

  • シングルトンはオブジェクトとして扱うことが出来るので、あるメソッドの引数に渡してやることが出来る。
  • シングルトンはインターフェースを利用できるのでモック化が楽。

結果として、シングルトンはテストやDI(依存注入)と相性が良いのが大きな強みです。staticクラスは「単純で書きやすい」が「テスト・差し替えに弱い」というトレードオフがあります。

コードでの違い(Java)

staticクラス(ユーティリティクラス)

public final class StringUtils {
    private StringUtils() {} // インスタンス化禁止

    public static boolean isEmpty(String s) {
        return s == null || s.isEmpty();
    }
}

// 呼び出し
StringUtils.isEmpty(name);

シングルトン

public class ConfigService {
    private static final ConfigService INSTANCE = new ConfigService();
    private ConfigService() {} // 外部からのnew禁止

    public static ConfigService getInstance() {
        return INSTANCE;
    }

    public String getEnvName() { /* ... */ }
}

// 呼び出し
ConfigService.getInstance().getEnvName();

使い分けの目安

場面推奨
状態を持たない純粋な関数群staticクラス(ユーティリティ)
システム全体で1つだけ持ちたい設定・キャッシュシングルトン(できればDIで管理)
テストでモックに差し替えたいシングルトン or DI
インターフェースを介して使いたいシングルトン
マルチスレッドで状態共有シングルトン(適切なロック設計)

近年のベストプラクティス

自前で getInstance() を実装するシングルトンより、DIコンテナ(Spring、Guice、CDI等)にシングルトンスコープで管理させるのが現在の主流です。テスト時に容易にモックへ差し替えられ、依存関係も明示できます。

// Spring の例: @Service / @Component で自動的にシングルトン
@Service
public class ConfigService {
    public String getEnvName() { /* ... */ }
}

// 利用側
@Autowired
private ConfigService configService;

注意点

  • シングルトンの濫用はグローバル状態を増やし、結合度が上がる
  • マルチスレッドでの初期化: synchronizeddouble-checked lockingenum singleton パターン
  • テスト時のリセットがしにくい場合は、DI管理にする
  • staticは継承できないため、機能拡張時に困ることがある

関連

編集
Post Share
子ページ

子ページはありません

同階層のページ

同階層のページはありません