2009-03-05 26 views
7

依存性注入を正しく実装する方法の1つは、オブジェクト作成とビジネスロジックを分離することです。通常、これはオブジェクト作成のためにファクトリを使用することを含みます。Factoryメソッドにパラメータを渡すことはできますか?

この時点までは、私は真剣にこの質問は少し単純化したと思われる場合ので、私は謝罪ファクトリーを使用して考えられたことがありません:

私は全体の実行したファクトリパターンのすべての例では、私はいつもパラメータ化を持たない非常に簡単な例を参照してください。たとえば、Misko Hevery'sという優れたHow To Think About the "new" Operatorの記事から工場を盗んだ場合などです。

 
class ApplicationBuilder { 
    House build() { 
    return new House(new Kitchen(
       new Sink(), 
       new Dishwasher(), 
       new Refrigerator()) 
      ); 
    } 
} 

しかし、私が建てた各家に名前を付けるとどうなりますか?このコードを次のように書き直すと、私はまだFactoryパターンを使用していますか?私のファクトリメソッドの呼び出しは、このから変更された

 
class ApplicationBuilder { 
    House build(const std::string & house_name) { 
    return new House(house_name, 
         new Kitchen(new Sink(), 
            new Dishwasher(), 
            new Refrigerator()) 
        ); 
    } 
} 

注:これに

 
ApplicationBuilder builder; 
House * my_house = builder.build();

:ところで

 
ApplicationBuilder builder; 
House * my_house = builder.build("Michaels-Treehouse");

:私は、オブジェクトを分離するという概念はビジネスロジックからインスタンス化すると思います私は自分の状況にどのように適用できるかを考えようとしています。私が混乱しているのは、Factoryパターンのすべての例では、build()関数にパラメータを渡すことはないということです。

明確にする:私はインスタンス化する必要がある瞬間まで家の名前を知らない。

+0

私がよく見たように、工場ではパラメータを取ることがあります。それには何も問題はありません。またはあなたの質問の点で。それは完全に大丈夫です。 – grieve

答えて

8

私はあなたの名前の例のような固定された引数のセットを使用し、それらを自分自身も使用していて、何か間違って見ることができない非常に多くの例を見てきました。

はしかし多くのチュートリアルや小物が構築されたオブジェクトにパラメータを転送する工場を示す避けるというもっともな理由があります:それは(たとえ6つの引数のようなまともな制限の)任意の数の引数を転送することは不可能事実上です。あなたが転送したい各パラメータは、const T&T&として受け入れなければなりません。

しかし、もっと複雑な例では、(パラメータごとにconstと非コンステートのバージョンに対して)指数関数的に増加するオーバーロードのセットが必要であり、perfect forwardingはまったく不可能です(例えば、テンポラリが一時的に転送されるように) 。次のC++標準のためにその問題は解決されています

class ApplicationBuilder { 
    template<typename... T> 
    House *build(T&&... t) { 
    return new House(std::forward<T>(t)..., 
         new Kitchen(new Sink(), 
            new Dishwasher(), 
            new Refrigerator()) 
        ); 
    } 
}; 

こうすることで、あなたは

builder.build("Hello", 13); 

を呼び出すことができますし、それが

new House("Hello", 13, new Kitchen(new Sink(... 

iは上記のリンク先の記事を読んで返します。

+0

右辺値の参照に関する良いリンク!それはおそらく質問の範囲を超えていますが、それは私がこのテーマで読んだ最も明白な記事の1つです。 –

5

このパラメータを工場に追加するのが間違っている理由はわかりません。しかし、工場で作成されたすべてのオブジェクトには役立たないかもしれない多くのパラメータを追加してはならないことに注意してください。そうすれば、工場の長所がかなり失われてしまうでしょう!

+0

どのような種類のオブジェクトを記述するか(paramsで)、これにより、ファクトリが完全に別のオブジェクトを返すことができます(ベースクラスまたはインタフェースを返すことによって)。 – Aardvark

1

私はBenoitに同意します。しかし、SQL接続のようなものを作成するためのファクトリを考えてみましょう。このような場合、接続に関する情報をファクトリに渡す必要があります。ファクトリは、その情報を使用して正しいサーバープロトコルなどを使用します。

4

ファクトリのアイデアは、クラス/インターフェイスのインスタンスを提供するということです。したがって、パラメータを渡すことに間違いはありません。もしあれば、new()にもパラメータを渡すのは悪いでしょう。

5

許容できるだけでなく、共通のパラメータをファクトリメソッドに渡します。チェックアウト:some examples通常、パラメータはファクトリに何を作るかを知らせるタイプですが、オブジェクトを構築するために必要なその他の情報を追加することはできません。あなたがやっていることは大丈夫だと思います。

1

パラメータを渡すと便利なことは、具体的なオブジェクトの実装を隠すことができることです。たとえば、投稿したコードでは、コンストラクタにパラメータを渡します。ただし、Initiailzeメソッドを経由するように実装を変更することができます。ファクトリメソッドにパラメータを渡すことで、呼び出し元からオブジェクトを構築して初期化する性質が隠されます。

1

Loki :: Factoryを見てください。しかし、Boostにも同様の実装があります。私は定期的に異なる味に使用するいくつかのサンプルコード:ロキのtypedef

:: SingletonHolder <ロキ::工場<コンポーネント、のstd ::文字列、ロキ::タイプリスト< constのDataCollection &、ロキ::タイプリスト<ゲーム*、ロキ:: NullType >> >>コンポーネントファクトリ;

これは一見するとちょっと変わって見えるかもしれませんが、私はこの獣とその実際の強さについて説明しましょう。基本的には、ファクトリを保持するシングルトンを作成します。ほとんどのパラメータはシングルトン用です。コンポーネントは、製品です.std :: stringは、作成IDタイプです。これは、コンポーネントの作成に必要なパラメータのタイプリストに従います。 (これは、あまり冗長でない構文に対してもマクロを使用して定義できます)。この行の後には、次のようにすることができます。

ComponentFactory :: Instance()。CreateObject( "someStringAssociatedWithConcreteType"、anDataCollection、aGamePointer);

オブジェクトを作成するには、ComponentFactory :: Instance()。Register();を使用します。 Modern C++ Designの本の中の詳細については、素晴らしい章があります。

関連する問題