Open10

Head First デザインパターン

takiguchetakiguche

1章 Strategy パターン

一連のアルゴリズムを定義してカプセル化し、交換できるようにする。Strategy パターンを使うと、アルゴリズムを利用するクライアントとは独立してアルゴリズムを変更できる。

設計原則

  • アプリケーション内の変化する部分を特定し、不変な部分と分離する。変化する部分は「カプセル化」する。すると、その部分はコードの他の部分に影響を及ぼさない。その結果、コード変更による予期せぬ結果が少なくなり、システムの柔軟性が向上する。
  • 実装に対してではなく、インターフェースに対してプログラミングする。Duckの振る舞いは別のクラス(特定の振る舞いインタフェースを実装したクラス)に配置する。
  • 継承よりコンポジションの方が好ましい。
    • 「HAS-A(〜を持つ)」は「IS-A(〜である)」より優れている場合がある
      • FlyBehavior と QuackBehavior のように2つのクラスを統合する際は、コンポジション(composition)を使用する。

サンプルコード

takiguchetakiguche

2章 Observer パターン

オブジェクト間の 1対多 の依存関係を定義し、あるオブジェクトの状態が変化すると、そのオブジェクトに依存しているすべてのオブジェクトに自動的に通知され更新されるようにする。Observer パターンでは、発行者(パブリッシャ)は「サブジェクト」と呼ばれ、購読者(サブスクライバ)は「オブザーバー」と呼ばれる。

設計原則

  • 相互にやりとりを行うオブジェクトの間には、疎結合設計を使う。
    • 疎結合設計はオブジェクト間の相互依存を最小限にするため、変更に対応できる柔軟なOOシステムを構築できる。

サンプルコード

takiguchetakiguche

3章 Decorator パターン

オブジェクトに追加の責務を動的に付与する。デコレーターは、サブクラス化の代替となる、柔軟な機能拡張手段を備える。

設計原則

  • クラスは拡張に対しては開かれた状態にするべきだが、変更に対しては閉じた状態にするべき。(開放/閉鎖原則またはオープンクローズドの原則)

サンプルコード

takiguchetakiguche

4章 Factory パターン

設計原則

抽象に依存する。具象クラスに依存してはいけない。(依存関係反転の原則または依存関係逆転の原則)
依存関係反転の原則はこちらの説明が分かりやすい。

Factory Method パターン

Factory Method パターンはオブジェクトを作成するためのインタフェースを定義するが、どのクラスをインスタンス化するかについてはサブクラスに決定させる。Factory Method により、クラスはサブクラスにインスタンス化を委ねることができる。

サンプルコード

Abstract Factory パターン

Abstract Factory パターンは、具象クラスを指定せずに、一連の関連オブジェクトや依存オブジェクトを作成するためのインターフェースを提供する。

サンプルコード

takiguchetakiguche

5章 Singleton パターン

クラスがインスタンスを1つしか持たないことを保証し、そのインスタンスにアクセスするグローバルポイントを提供する。

使用例

  • 共有リソースへのアクセス: データベース接続や設定ファイルへのアクセスなど、アプリケーション全体で共有するリソースにアクセスするとき。
  • ログ記録: アプリケーション全体で一つのログファイルに書き込むときなど、同じロガーオブジェクトを使用する場合。
  • 状態管理: アプリケーションのライフサイクル全体で持続するような状態を持つオブジェクトの場合。

典型的な Singleton パターンの実装例

// NOTE: この実装はスレッドセーフではありません!

public class Singleton {
  private static Singleton uniqueInstance;

  private Singleton() {}  // コンストラクタを private にすることで、外部からのインスタンス化を防ぐ

  // 唯一のインスタンスを返すメソッド
  public static Singleton getInstance() {
    if (uniqueInstance == null) {
      uniqueInstance = new Singleton();
    }
    return uniqueInstance;
  }
}

マルチスレッド、遅延インスタンス作成、二重チェックロッキングを考慮した実装例

マルチスレッドを実現するために単純に synchronized (同期化)した場合、実行の度に同期化されるためオーバーヘッドが大きい。初回以降はインスタンス作成をしないように実装する。また、並列処理で複数インスタンスが作成されないように二重チェックロッキングを使う。

public class Singleton {
  private volatile static Singleton uniqueInstance;  // volatile は変数をマルチスレッド処理するための修飾子

  private Singleton() {}

  public static Singleton getInstance() {
    if (uniqueInstance == null) {  // インスタンスの有無を調べる
      synchronized (Singleton.class) {  // 同期ブロック
        if (uniqueInstance == null) {  // 初回実行時のみインスタンス化
          uniqueInstance = new Singleton();
        }
      }
    }
    return uniqueInstance;
  }
}

サンプルコード

takiguchetakiguche

6章 Command パターン

リクエストをオブジェクトとしてカプセル化し、その結果、クライアントをさまざまなリクエスト、キュー、またはログリクエストでパラメータ化し、アンドゥ可能な操作もサポートする。
リクエストを行うオブジェクトとそのリクエストの実行方法を知っているオブジェクトを分離したい場合に Command パターンを使う。

RemoteLoader実装例
public class RemoteLoader {
 
  public static void main(String[] args) {
    RemoteControlWithUndo remoteControl = new RemoteControlWithUndo();
 
    Light livingRoomLight = new Light("Living Room");
 
    LightOnCommand livingRoomLightOn = 
        new LightOnCommand(livingRoomLight);
    LightOffCommand livingRoomLightOff = 
        new LightOffCommand(livingRoomLight);
 
    remoteControl.setCommand(0, livingRoomLightOn, livingRoomLightOff);
 
    remoteControl.onButtonWasPushed(0);
    remoteControl.offButtonWasPushed(0);
    System.out.println(remoteControl);
    remoteControl.undoButtonWasPushed();
    remoteControl.offButtonWasPushed(0);
    remoteControl.onButtonWasPushed(0);
    System.out.println(remoteControl);
    remoteControl.undoButtonWasPushed();
  }
}

サンプルコード

takiguchetakiguche

7章 Adapter パターンと Facade パターン

設計原則

最小知識の原則(Principle of Least Knowledge): オブジェクト間のやり取りを少数の身近な「友達」だけに減らすようにするという指針である。

Adapter パターン

クラスのインタフェースをクライアントが要求する別のインタフェースに変換する。アダプタは、インターフェースの互換性がないためにそのままでは連携できないクラスを連携させる。

サンプルコード

Facade パターン

サブシステムの一連のインタフェースに対する、統合されたインタフェースを提供する。ファサードは、サブシステムを使いやすくする高水準インタフェースを定義する。

サンプルコード

takiguchetakiguche

8章 Template Method パターン

メソッド内でアルゴリズムの骨組みを定義し、一部の手順をサブクラスに委ねる。Template Method はアルゴリズムの構造を変えることなく、アルゴリズムのある手順をサブクラスに再定義させる。

ハリウッドの原則

こちらを呼び出すな。こちらから呼び出す。(Don't call us, we'll call you.)スーパークラスが主導権を握り、ハリウッドにおける習慣のようにサブクラスを必要とするときにスーパークラスがサブクラスを呼び出す。

具象メソッド customerWantsCondiments() が true を返すことを調べる条件式を追加。客がコンディメンとを「希望する」場合のみ、 addCondiments() を呼び出す。

public abstract class CaffeineBeverageWithHook {
 
  final void prepareRecipe() {
    boilWater();
    brew();
    pourInCup();
    if (customerWantsCondiments()) {
      addCondiments();
    }
  }
  // 省略 

サンプルコード

takiguchetakiguche

9章 Iterator パターンと Composite パターン

設計原則

クラスは変更される理由を一つだけ持つべきである。(単一責務の原則)
クラスの責務は、変更される可能性のある部分に及ぶ。複数の責務を持つことは、変更される可能性のある部分が複数あることを意味する。

Iterator パターン

内部表現を公開せずに、アグリゲートオブジェクトの要素に順次アクセスする方法を提供する。

サンプルコード

Composite パターン

オブジェクトをツリー構造に構成して部分−全体階層を表現できる。Composite パターンにより、クライアントは個々のオブジェクトとオブジェクトのコンポジションを統一的に扱える。

サンプルコード