Factory Method〜インスタンス生成宣言の重複排除〜 <- 言葉で理解するデザインパターン <- TetraCalibers
TetraCalibers :
    -   for : science student & programmer
言葉で理解するデザインパターン - 2
Factory Method
インスタンス生成宣言の重複排除

     

    動機となる問題

     

    コンストラクタを使ってnewする場合、クライアント側のコードにクラス名が散らばることになる。

     

    複数クラスをクライアント側で使い分ける場合、各クラスの役割と引数構成をクライアント側がすべて把握しておく必要がある。

     

    どちらにせよ、クラスを切り替える場合やクラスの引数構成が変わった時に、クライアント側のコードに散らばったインスタンス生成コードをすべて書き換える必要が生じる。

     

    [基本形]複数クラスの同一視

     

    クラスAはテスト用のクラスで、後に本番用のクラスBに置き換える予定でいるとする。

     

    1. 今後変更する可能性のあるクラス群A・B(ConcreteProduct)を一般化した抽象クラスX(Product)を作成する
    2. クラスAのインスタンスもBのインスタンスもX型のオブジェクトとして同一視できるように、クラスAとクラスB(ConcreteProduct)はクラスX(Product)を継承するようにする
    3. クラスX(Product)内にクラスAのインスタンス化処理を行うメソッド(createメソッド)を用意する
    4. クライアント側(Client)では、クラスX(Product)のcreateメソッドを使ってオブジェクトを利用するようにする
    5. クラスBに切り替える時は、クラスX(Product)のcreateメソッドを変更すればよい

     

    どのクラスを使うかをクライアント側で決定したい場合

     

    基本はクラスBを使うが、障害発生時にはクラスAに切り替えられるようにしたい場合を考える。

     createメソッドの引数としてどちらのオブジェクトを生成するかを指定してもよいが、これでは結局特定のクラスを指定する記述がクライアント側のコードに散らばることになる。

     

    すると、仮に障害発生時にクラスCを使うように変更した場合、クラスAを指定したcreateメソッド呼び出し箇所すべてを変更する羽目になり、基本形適用前と似た悪状況に直面する。

     

    • クライアント側のコードでも、どのオブジェクトを呼び出すかの指定は一箇所で済むようにしたい

     

    そのために、X型オブジェクトの生成を担当するクラス(工場:factory)を用意し、Factoryインスタンスを生成する際にのみどのオブジェクトを生成するかを指定することにする。

     

    [発展形1]引数に応じてオブジェクトを生成する工場を用意

     

    1. Xfactoryクラス(ConcreteCreator)を新設し、そのコンストラクタではA・Bのどちらを生成するかを指定する引数を受け取り、privateなクラス変数(type)として保持するようにする
    2. Xfactoryクラス(ConcreteCreator)のcreateメソッドでは、クラス変数typeの値に応じて生成するオブジェクトを分岐させるようにする
    3. クライアント側(Client)では、プログラムの冒頭でA型オブジェクト用のXfactoryインスタンスとB型オブジェクト用のXfactoryインスタンスをそれぞれ生成しておく。
    4. 以降、AまたはBのオブジェクトが欲しい時には、各オブジェクト用のXfactoryインスタンスのcreateメソッドを介してオブジェクトを生成するようにする。

     

    クラスの選択肢を増やしたい場合の問題

     

    通常稼働時の選択肢として、クラスDを追加したい場合を考える。

     

    この場合、Xfactoryクラスのコンストラクタ引数による条件分岐にクラスDが指定された場合も追記する必要があるが、そもそも既存クラスのコード修正にはリスクを伴う。

     

    • 既存クラスを修正することなく、新たなクラスを追加するだけで選択肢を増やすことができるようにしたい

     

    [発展形2]各オブジェクトを生成する専門工場をそれぞれ作成

     

    • Xfactoryクラスを、createメソッドを宣言するインターフェースに変更
    • Xfactoryインターフェース(Creator)を継承して、Afactoryクラス・Bfactoryクラス(ConcreteCreator)を作成する
    • クライアント側(Client)では、使いたいオブジェクト用のfactoryクラス(ConcreteCreator)のcreateメソッドでオブジェクトを作成する
    • クラスDを追加したければ、Xfactoryインターフェース(Creator)を継承してDfactoryクラス(ConcreteCreator)を実装し、Dfactoryクラス(ConcreteCreator)のcreateメソッドをクライアント側のコードで使えばよい