ちょっと途方もない処理ですが、勘弁してください。スープラもロードスターも、どちらも作り上げるのは
非常に大変ですが、似たようなものです。まず、エンジンやドアなどの部品を作って、
次にそれらの部品を組み立て、最後に安全性などをテストを行います。
しかし、スープラとロードスターでは、使われるエンジンもドアも組み立て方も違いますよね。
全体の流れは似ていても、その1つ1つの具体的な処理は異なります。また、それは非常に複雑なものです。
こういう時はBuilderパターンを適用します。
Builderパターンを適用する時に注意するのは、複雑なインスタンス生成を、単にメソッドに分けるだけでなく、
そのメソッド呼び出しをコントロールするクラスを作成するという点です。実はBuilderパターンは、
Template Methodパターンと似ていますが、
この部分が大きく違います。Template Methodパターンでは、スーパークラスがサブクラスの具体的な
処理手順をコントロールしました。ですが、Builderパターンでは他のクラスがBuilderクラス(インスタンスを
生成するクラス)の処理手順をコントロールします。ここでいう「他のクラス」、
つまり、Builderクラスの処理手順をコントロールするクラスのことをDirectorクラスと呼びます。
なぜ他のクラスにコントロールさせるかというのは、後でお話します。
話を例に戻すと、Builderクラスとしてスープラを作るクラスと、ロードスターを作るクラスが
必要そうですよね。ただし先にも書いたように、どちらも車を作るわけですから、
「車を作る」というクラスを定義してそれを継承させた方が良さそうです。
また、上で説明したように、BuilderパターンにはDeirectorクラスも必要です。
ここまでで必要なクラスを洗い出すと以下のようになります。
CarBuilder |
「車を作る」抽象クラス |
SupuraBuilder |
「スープラを作る」クラス |
RoadstarBuilder |
「ロードスターを作る」クラス |
Director |
「車を作る」ことを管理するクラス |
では具体的にどういった手順で車を作成するのでしょうか?
ユーザはDirectorクラスに車を作ることを委譲します。Directorクラスは、コンストラクタで与えられた
CarBuilderクラスの車を作成します。この時大切なのが、Directorクラスのコンストラクタには、
CarBuilderクラス型の変数を与えるということです。インタフェースプログラミングのポイントは、
インタフェースを与えるべきところにはそのインタフェースを実装したオブジェクトなら
何でも入れられという点です。ですから、Direcotrには、SupuraBuiderでも、RoadstarBuiderでも渡せますし、
後から追加するかも知れないFerrariBuilderやBmwBuilderも、それらがCarBuilderを継承しているなら
渡すことが可能です。
また、何故Directorクラスにインスタンス生成を委譲するのか、という点についてお話します。
今回の例で言うと、Mainクラスで直接、CarBuilderクラスのgetCarメソッドを呼び出してもよさそうです
(もちろん、その場合にはabstractではなく、内部を実装しなければなりません)。MainからDirectorへ、
DirectorからCarBuilderへと処理を委譲するのは、MainがCarBuilderの詳細を意識することなく、
CarBuilderを差し替えられるようにするためです。mainメソッド内では、Directorクラスのメソッドしか
使われていません。ユーザはDirecotrクラスだけを気にかければ良く、CarBuilderやそのサブクラスの詳細を
知る必要はないのです。また同時に、それぞれのクラスの責務を分散することが出来ます。
Builderは車を作らなければなりません。車の作る過程は複雑で、その過程まで管理するとなると、
Builderクラスは膨れ上がってしまいます。ですが、Builderパターンを適用すると、Builderクラスは
車を作る1つ1つの処理だけについて定義し、実際に車を作り上げるのはDirectorクラスになります。
|