web-dev-qa-db-ja.com

ファクトリパターンはオープン/クローズド原則に違反していますか?

このShapeFactoryが条件付きステートメントを使用して、インスタンス化するオブジェクトを決定するのはなぜですか。今後、他のクラスを追加する場合は、ShapeFactoryを変更する必要はありませんか?なぜこれがオープンクローズの原則に違反しないのですか?

Factory Pattern Design

ShapeFactory Design

14
Armon Safai

従来のオブジェクト指向の知識は、ifステートメントを回避し、抽象クラスのサブクラス内のオーバーライドされたメソッドの動的ディスパッチに置き換えることです。ここまでは順調ですね。

しかし、ファクトリーパターンの要点は個々のサブクラスについて知る必要がなくなり、抽象スーパークラスでのみ機能するようにするためです。アイデアは、インスタンス化する特定のクラスをファクトリーがあなたよりよく知っているということであり、スーパークラスによってパブリッシュされたメソッドでのみ作業するほうがよいでしょう。これはしばしば真実であり、価値あるパターンです。

したがって、ファクトリクラスを作成してもifステートメントを無視することはできません。これは、特定のクラスを選択する負担を呼び出し元にシフトします。つまり、パターンが回避するはずの正確にです。すべての原則が絶対的であるとは限りません(実際、no原則は絶対的です)。このパターンを使用する場合は、ifを使用しない場合の利点よりもこのパターンの利点の方が大きいと想定します。

20
Kilian Foth

この例は最も簡単であるため、おそらく条件付きステートメントを使用します。より複雑な実装では、マップまたは構成を使用するか、または(本当に凝ったものにしたい場合は)クラスが自分自身を登録できるある種のレジストリを使用します。ただし、クラスの数が少なく、変更頻度が低い場合は、条件付きを使用しても問題はありません。

将来的に新しいサブクラスのサポートを追加するために条件を拡張することは、厳密に言えば厳密に言えば、オープン/クローズの原則に違反することになります。 「正しい」解決策は、同じインターフェースで新しいファクトリーを作成することです。とはいえ、O/C原則の遵守は、KISSやYAGNIなど)の他の設計原則と常に比較検討する必要があります。

とはいえ、表示されるコードは明らかにファクトリーの概念を示すために設計されたサンプルコードであり、他には何もありません。例えば。例のようにnullを返すのは本当に悪いスタイルですが、より複雑なエラー処理は要点を曖昧にするだけです。サンプルコードは本番品質のコードではなく、期待どおりのものではありません。

5
JacquesB

パターン自体は、Open/Closed Principle(OCP)に違反していません。ただし、パターンを誤って使用すると、OCPに違反します。

この質問に対する簡単な答えは次のとおりです。

  1. Factory Methodパターンを使用して、基本機能を作成します。
  2. [〜#〜] extend [〜#〜]Abstract Factoryを使用した機能パターン

提供されている例では、基本機能は3つの形状(Circle、Rectangle、Square)をサポートしています。将来的にTriangle、Pentagon、Hexagonをサポートする必要があるとします。これを行うには[〜#〜]なし[〜#〜] OCPに違反しているため、新しい形状をサポートする追加のファクトリを作成し(AdvancedShapeFactoryと呼びましょう)、次にAbstractFactory必要な形状を作成するために作成する必要があるファクトリを決定します。

2
hfontanez

Abstract Factoryパターンについて話している場合、意思決定は多くの場合Factory自体ではなく、アプリケーションコードで行われます。インスタンス化する具体的なファクトリを選択し、ファクトリによって生成されたオブジェクトを使用するクライアントコードに渡すのは、そのコードです。 Javaの例の終わりを参照してください: https://en.wikipedia.org/wiki/Abstract_factory_pattern

意思決定は必ずしもifステートメントを意味しません。具体的なFactoryタイプを構成ファイルから読み取ったり、マップ構造から派生したりできます。

1
guillaume31

このファクトリを使用してクラスレベルでOpen-Closeを考える場合、たとえば、1つのShapeを取り、面積を計算する他のクラス(典型的な例)がある場合、このクラスはOpenCloseです。新しいタイプの形状の面積を変更せずに計算できます。次に、形状を描画する別のクラス、N個の形状を取り、より大きなものを返す別のクラスがあり、一般に、形状を処理するシステム内の他のクラスは開閉です(少なくとも形状について)。設計を見てみると、工場の残りの部分は開閉可能であり、工場自体が開閉ではなくITSであることを確認できます。

もちろん、ある種の動的ロードを介してこのファクトリーを開閉することもでき、システム全体を開閉することができます(たとえば、クラスパスにjarをドロップする新しい形状を追加できます)。すべてのシステムがプラグイン可能な機能を必要とするわけではなく、すべてのシステムが完全にオープン/クローズである必要はありません。

0
AlfredoCasado

Liskov置換原理としての開閉原理は、クラスツリー、継承階層に適用されます。あなたの例では、ファクトリークラスはインスタンス化されたクラスのファミリーツリーにないので、これらのルールに違反することはできません。 GetShape(またはより適切な名前が付けられたCreateShape)がShape基本クラスで実装されている場合、違反が発生します。

0
Martin Maat