Java上級

上級 Javaで学ぶデザインパターン|アンチパターン編

導入

デザインパターンはソフトウェア開発において、再利用可能な解決策を提供します。しかし、実際の現場では設計の意図を誤解し、アンチパターンに陥ることが少なくありません。このセクションでは、Javaを用いた具体的なシナリオを通じて、一般的なアンチパターンとその改善方法を見ていきます。

教科書レベルの解説(デザインパターン)

重要な概念の整理

デザインパターンは、オブジェクト指向プログラミングの原則に基づいており、特定の問題に対する汎用的な解決方法を示します。特に、シングルトンやファクトリーパターンなどは、オブジェクトの生成や管理において非常に役立ちます。しかし、これらのパターンを誤用すると、コードの可読性やメンテナンス性が低下することがあります。

コード例(Java)


public class UserManager {
    private static UserManager instance;

    private UserManager() {}

    public static UserManager getInstance() {
        if (instance == null) {
            instance = new UserManager();
        }
        return instance;
    }

    public void addUser(String user) {
        // ユーザー追加のロジック
    }
}

コードの行ごとの解説

  1. 1行目:UserManagerクラスを定義します。
  2. 2行目:シングルトンインスタンスを保持するための静的変数を宣言します。
  3. 4行目:プライベートコンストラクタにより、外部からのインスタンス生成を防ぎます。
  4. 6行目:インスタンスが未生成の場合のみ新たに生成します。
  5. 9行目:ユーザーを追加するためのメソッドを定義します。

アンチパターン編

上記のコードはシングルトンパターンの実装例ですが、スレッドセーフでないため、複数のスレッドからアクセスされると問題が発生します。例えば、2つのスレッドが同時にgetInstanceメソッドを呼び出すと、2つのインスタンスが生成される可能性があります。

この問題を解決するためには、メソッドをsynchronizedで修飾するか、ダブルチェックロッキングを使用します。以下はその改善例です。


public class UserManager {
    private static UserManager instance;

    private UserManager() {}

    public static UserManager getInstance() {
        if (instance == null) {
            synchronized (UserManager.class) {
                if (instance == null) {
                    instance = new UserManager();
                }
            }
        }
        return instance;
    }

    public void addUser(String user) {
        // ユーザー追加のロジック
    }
}

この改善により、スレッドセーフなシングルトンが実現され、同時アクセスによるインスタンスの重複生成を防げます。

まとめ

  • デザインパターンは適切に使用されるべきであり、誤用するとアンチパターンに陥る。
  • シングルトンパターンの実装にはスレッドセーフを考慮する必要がある。
  • 問題を解決するための適切な手法を選択することが、コードの品質を高める。