ファクトリメソッドのデザインパターンが、クラスを作成して個別に呼び出すよりも便利なのはなぜですか?


32

「4つのギャング」デザインパターンから、ファクトリメソッドがあります。

class Factory(product)
  case product
  when a
    new A
  when b
    new B
  when c
    new C
end

new Factory(a)

なぜこれが、3つのクラスが持つよりも有用であるabcし、それらを個別に呼び出しますか?


1
正確にはどういう意味ですか?3つすべてをインスタンス化しないのはなぜですか?それはあなたの言うことですか?
ニール

1
@Neilいいえ、ファクトリー・パターンでは、すべてのクラスが兄弟として存在します。なぜファクトリを呼び出して、a、b、cクラスに間接的にアクセスするのですか?
alt

3
抽象的な工場への近いどちらかといえば、これは実際には、私にはFactory Methodパターンのようにしていません
JK。

2
設計時には、3つのクラスのどれをインスタンス化する必要があるかわからないからです。
MrWhite

2
@jk:いいえ、本当にありません。programmers.stackexchange.com/questions/81838/...
PDR

回答:


54

あなたの例は十分に複雑ではないからです。このような単純なシナリオでは、高度なパターンを使用することも意味がありません。

しかし、A、B、またはCを構築するために製品以上のことを知る必要があり、その知識に直接アクセスできない場合、それは役に立ちます。次に、ファクトリを使用して、必要なオブジェクトを生成するためのナレッジセンターとして機能します。

これらのオブジェクトには、ファクトリが提供できるオブジェクトXへの参照が必要な場合がありますが、A、B、またはCを構築する場所のコードは、Xにアクセスできないか、アクセスするべきではありません。 AとBを作成しますが、Yタイプがある場合はCを作成します。

また、作成するのに20個の依存関係が必要なオブジェクトがあることも考慮してください。それで何?アクセスできないはずの場所でそれらの依存関係を探しに行くのは問題があるかもしれません。


13
ファクトリーパターンが常に最良のアプローチではないことを明確にするために+1。
ニール

1
あなたの例は十分に複雑ではないからです。このような単純なシナリオでは、高度なパターンを使用することすら意味がありません。この場合、あなたはどうしますか?条件構成をインライン化しますか?
pdr

これは、製品を受け取り、それを再利用可能にするために必要なものを返すだけのメソッドであるため、インラインである必要はありません。そのようなメソッドがより大きなものに成長した場合、または他のいくつかのクラスで使用されている場合、別のクラスにリファクタリングできます。
マテウス

このパターンは、理由によりファクトリメソッドと呼ばれます。このメソッドは、ファクトリメソッドになるために別のクラスにある必要はありません(多くの場合そうです)。
pdr

私はその中の「方法」を見逃したので、あなたはまさにミスターです。
マテウス

23

通常、ファクトリパターンはそれよりも複雑です。工場は特定の基準で、どのインスタンスを作成/返却するかを決定します。代わりに、ファクトリを使用しない場合、コード内の複数の場所でそのコードを繰り返し使用することになります。

例として、DBからデータをロードする必要がありますが、大量のデータと統合するために1つの中央DBがあり、各開発PCのメモリに1つの小さいDBがあります。コード内で、ファクトリにDBハンドルを取得するように要求すると、ファクトリは、たとえば構成ファイルに応じて、それらのいずれかを返します。


20

Factory Methodパターンは、呼び出し側クラスから意思決定プロセスを抽象化します。これにはいくつかの利点があります。

再利用。多くの場所でインスタンス化する場合、条件を繰り返す必要はありません。そのため、新しいクラスを追加するときに、クラスが欠落するリスクはありません。

ユニットテスタビリティ。ファクトリーに対して3つのテストを作成し、正しい条件で正しい型を返すことを確認し、呼び出し元のクラスをテストするだけで、ファクトリーを呼び出してから、返されたクラスで必要なメソッドを呼び出すことができます。ファクトリ自体または具象クラスの実装について何も知る必要はありません。

拡張性。誰かがこのファクトリに新しいクラスDを追加する必要があると判断した場合、呼び出しコード、ユニットテスト、実装のいずれも通知する必要はありません。新しいクラスDを作成し、ファクトリメソッドを拡張するだけです。これは、Open-Closed Principleのまさに定義です。

テスト中にクラスDのオンとオフを切り替えたい場合など、状況に応じて、新しいファクトリクラスを作成し、ホットスワップ可能にすることもできます。この状況に遭遇したのは一度だけですが、非常に役に立ちました。

既に述べたように、ファクトリーパターンは必ずしも進むべき道ではありません。ただし、条件付きインスタンス化が表示される場合はいつでも、少し考えてみてください。


14

Factoryパターンの主な利点は2つあります。

  1. 製品の実装が必要な場所は、製品の構築方法を知る必要はありません。工場はその情報を保持しています。

    特定のコンストラクターに渡す引数を知りたいですか?または、どの依存関係を注入する必要がありますか?または、完全に構成された後に実装クラスをデータベースに登録する方法は?いや?工場にすべてのことを見てもらいましょう。

  2. 製品の実装を必要とする場所は、モジュールの記述時(つまり、コンパイル時)に実装クラスの名前を知る必要はありません。

    したがって、a何もする必要はありませんA。「構築するもの」は、名前だけでなく、目的の非機能プロパティの観点から説明できます。これははるかに柔軟です。

欠点は、何をどのように作成するかを知っていると、ファクトリーを使用するときに複雑さが増すことです。ただし、それに対する修正は簡単です。意味をなさない場合はファクトリを使用しないでください。


2

クラスが「人」であるという観点から、デザインパターンについて考えたいと思います。パターンは、人々が互いに話す方法です。

ですから、私にとって、工場のパターンは雇用機関のようなものです。可変数のワーカーが必要な人がいます。この人は、雇う人に必要な情報を知っているかもしれませんが、それだけです。

そのため、新しい従業員が必要になったとき、雇用代理店に電話して必要なものを伝えます。さて、実際に誰かを雇うには、多くのことを知っておく必要があります-福利厚生、資格の確認など。しかし、雇用する人はこれを知る必要はありません。

同様に、ファクトリを使用すると、コンシューマは作成方法や依存関係の詳細を知る必要なく、新しいオブジェクトを作成できます。実際に必要な情報を提供するだけです。

礼儀


1

Factoryパターンは、最も頻繁に使用され、乱用されたデザインパターンです。

単純なコンストラクターで十分な場合にFactoryクラスがコーディングされるという多くのケースに遭遇しました。

次の場合を除き、ファクトリクラスを使用しないでください。

  • 外部リソースに依存していますが、まだどのリソースか正確にはわかりません。
  • 建設は高価であり、一度構築して何度も再利用したいです。
  • 新しいインスタンスの構築は、どのインスタンスが既に構築されているかによって異なります(たとえば、接続は5つしか接続できない、または最後に使用した番号よりも1つ多い接続IDを使用する必要があります)。

0

サブクラスをインスタンス化するときにファクトリメソッドを使用します。クライアントコードは、どの特定のサブクラスをインスタンス化するかを決定する責任を負っていません。

インスタンス化するクラスを変更する必要があるときにクライアントコードを変更する必要がないため、便利です。既存のコードを変更することは、通常エラーが発生しやすいため、悪い習慣です。

例としては、サブクラスがあり、各サブクラスはデータを昇順で並べ替えますが、方法は異なります。それぞれの方法は、特定の種類のデータに最適です。例:部分的にソートされたデータ、数字などのデータ。クライアントコードは、データの印刷のみを処理するクラスです。どのソートクラスをクライアントクラスでインスタンス化するかを決定するコードがあると、複雑なクラスになります。言い換えると、この場合、複数の責任を持つことは、どのソートクラスが最適であるかを決定し、データを印刷します。どのソートクラスをインスタンス化するかを決定するコードをFactoryクラスに入れることにより、懸念を分離し、どのソートサブクラスがインスタンス化されるかを変更する必要があるたびにクライアントクラスを変更する必要がなくなります。

クラスをインスタンス化する方法やクラスの自己決定的な変化を予測できる場合、それはあなたの腕をカバーする方法です。ファクトリクラスは使用する意味があります。これにより、クラスが1つの責任に集中できるようになり、その結果、関連していない既存のコードを変更する必要が少なくなります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.