Factoryメソッドにパラメーターを渡しても大丈夫ですか?
-
03-07-2019 - |
質問
依存性注入を正しく実装する方法の1つは、オブジェクトの作成をビジネスロジックから分離することです。通常、これには、オブジェクトの作成にファクトリを使用することが含まれます。
この時点まで、ファクトリーの使用を真剣に検討したことはなかったため、この質問が少し単純化されているように思える場合は謝罪します。
私が遭遇したファクトリパターンのすべての例では、パラメーター化されていない非常に単純な例が常に見られます。たとえば、 Misko Hevery's の優れた <!> quot; new <!> quot;の考え方演算子の記事。
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()) ); } }
Factoryメソッドの呼び出しがこれから変更されていることに注意してください:
ApplicationBuilder builder; House * my_house = builder.build();
これへ:
ApplicationBuilder builder; House * my_house = builder.build("Michaels-Treehouse");
ところで、オブジェクトのインスタンス化とビジネスロジックを分離する概念は素晴らしいと思います。自分の状況にそれをどのように適用できるかを考えています。私を混乱させているのは、Factoryパターンで見たすべての例がbuild()関数にパラメーターを渡さないことです。
明確にするために、私はそれをインスタンス化する必要がある直前まで家の名前を知りません。
解決
名前の例のように、固定された引数セットを使用する例が非常に多く見られますが、自分でも使用しているので、問題は見られません。
ただし、多くのチュートリアルまたは小さな記事では、構築されたオブジェクトにパラメーターを転送するファクトリーを表示しないようにする正当な理由があります:任意の数の引数を転送することは実際には不可能です6つの引数)。転送する各パラメーターは、汎用的に実行する場合は、const T&
およびT&
として受け入れる必要があります。
ただし、より複雑な例では、指数関数的に増加するオーバーロードのセット(各パラメーター、constおよびnonconstバージョン)と完全な転送は不可能です(そのため、一時的にたとえば、一時的。次の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の記事を読んでください。
他のヒント
このパラメーターをファクトリーに追加することが間違っている理由がわかりません。ただし、ファクトリによって作成されたすべてのオブジェクトに役立つとは限りませんが、多くのパラメーターを追加しないでください。そうすれば、工場の利点の多くを失うことになります!
受け入れられるだけでなく、パラメータをファクトリメソッドに渡すのは common です。 いくつかの例をご覧ください。通常、パラメーターは何を作成するかをファクトリに指示する型ですが、オブジェクトを作成するために必要な他の情報を追加できない理由はありません。あなたがやっていることは素晴らしいと思います。
ファクトリの概念は、クラス/インターフェイスのインスタンスを提供するということです。そのため、パラメータを渡すことに何の問題もありません。存在する場合、new()にもパラメーターを渡すのは良くありません。
ブノワに同意します。ただし、SQL接続のようなものを作成するためのファクトリーを考えてください。このような場合、接続に関する情報をファクトリーに渡す必要があります。ファクトリはその情報を使用して、正しいサーバープロトコルなどを使用します。
もちろん、どうして....!?
パラメータを渡すことの良いところは、具象オブジェクトの実装を隠すことができることです。たとえば、投稿したコードでは、パラメーターをコンストラクターに渡します。ただし、初期化メソッドを介して渡されるように実装を変更できます。ファクトリメソッドにパラメーターを渡すことにより、呼び出し元からオブジェクトを構築および初期化する性質を隠します。
Loki :: Factoryを見てください。しかし、Boostにも同様の実装があります。さまざまなフレーバーで定期的に使用するコード例:
typedef Loki :: SingletonHolder <!> lt; Loki :: Factory <!> lt;コンポーネント、std :: string、Loki :: Typelist <!> lt; const DataCollection <!> amp ;, Loki :: Typelist <!> lt; Game *、Loki :: NullType <!> gt; <!> gt; <!> gt; <!> gt; ComponentFactory;
これは一見奇妙に思えるかもしれませんが、この獣とそれがどれほど強力かを説明させてください。基本的に、ファクトリを保持するシングルトンを作成します。ほとんどのパラメータはシングルトン用、Componentは製品、std :: stringは作成IDタイプです。これは、コンポーネントの作成に必要なparamsのタイプリストに従います。 (これは、より冗長な構文のためにマクロを使用して定義できます)。この行の後、次の操作を実行できます。
ComponentFactory :: Instance()。CreateObject(<!> quot; someStringAssociatedWithConcreteType <!> quot ;, anDataCollection、aGamePointer);
オブジェクトを作成するには、ComponentFactory :: Instance()。Register();を使用してオブジェクトを登録します。 「モダンC ++デザイン」という本には、詳細に関する素晴らしい章があります。