このShapeFactoryが条件付きステートメントを使用して、インスタンス化するオブジェクトを決定するのはなぜですか。将来他のクラスを追加する場合、ShapeFactoryを変更する必要はありませんか?なぜこれはオープンクローズド原則に違反しないのですか?
このShapeFactoryが条件付きステートメントを使用して、インスタンス化するオブジェクトを決定するのはなぜですか。将来他のクラスを追加する場合、ShapeFactoryを変更する必要はありませんか?なぜこれはオープンクローズド原則に違反しないのですか?
回答:
従来のオブジェクト指向の知恵は、if
ステートメントを回避し、抽象クラスのサブクラスでオーバーライドされたメソッドの動的ディスパッチでそれらを置き換えることです。ここまでは順調ですね。
しかし、ファクトリパターンのポイントは、個々のサブクラスについて知る必要がなく、抽象スーパークラスのみで作業することから解放することです。アイデアは、どの特定のクラスをインスタンス化するかをファクトリがあなたよりよく知っているということであり、スーパークラスによって公開されたメソッドでのみ作業する方が良いでしょう。これはしばしば真実であり、価値のあるパターンです。
したがって、ファクトリクラスをif
記述することでステートメントを無視することはできません。それは、呼び出し元に特定のクラスを選択する負担シフトする正確パターンは避けるようになっているものを。いないすべての原則は、(実際には、絶対的無原則は絶対的ではありません)、そしてあなたは、このパターンを使用する場合は、それからの利益は、使用していないの利益よりも大きいことを前提としたいですif
。
if
です。これを実現する方法の簡単な例については、@BЈовићの回答を参照してください。ダウン投票。
この例では、最も単純であるため、おそらく条件ステートメントを使用します。より複雑な実装では、マップまたは構成を使用するか、クラスを自分で登録できる何らかのレジストリを使用する場合があります。ただし、クラスの数が少なく、頻繁に変更されない場合、条件を使用しても問題はありません。
将来、条件を拡張して新しいサブクラスのサポートを追加することは、厳密に言えば、オープン/クローズの原則に違反することになります。「正しい」解決策は、同じインターフェースを持つ新しいファクトリーを作成することです。ただし、O / C原則の遵守は、KISSやYAGNIなどの他の設計原則と常に比較検討する必要があります。
とはいえ、表示されるコードは明らかに工場の概念を示すために設計されたサンプルコードであり、それ以外は何もありません。たとえば、例のようにnullを返すのは本当に悪いスタイルですが、より複雑なエラー処理ではポイントがわかりにくくなります。サンプルコードは製品品質のコードではありません。
パターン自体は、Open / Closed Principle(OCP)に違反しません。ただし、パターンを誤って使用すると、OCPに違反します。
この質問に対する簡単な答えは次のとおりです。
提供された例では、基本機能は円、長方形、正方形の3つの形状をサポートしています。将来、三角形、五角形、六角形をサポートする必要があるとします。これを行うにはなし OCPに違反し、あなたの新しい形を(と呼ばれるのを聞かせてサポートするための追加の工場作成する必要がありますAdvancedShapeFactory
使用した後)とAbstractFactoryあなたが必要な形状何でも作成するために作成するために必要なものを工場決めることを。
Abstract Factoryパターンについて話している場合、意思決定は多くの場合、ファクトリ自体ではなく、アプリケーションコードで行われます。インスタンス化する具体的なファクトリを選択し、ファクトリによって生成されたオブジェクトを使用するクライアントコードに渡すのは、そのコードです。Javaの例の最後を参照してください:https : //en.wikipedia.org/wiki/Abstract_factory_pattern
意思決定は必ずしもif
陳述を意味するものではありません。構成ファイルから具体的なFactoryタイプを読み取り、マップ構造などから派生させることができます。
このファクトリを使用してクラスレベルで開閉を考える場合、たとえば、1つのShapeを取得して面積を計算する他のクラスがある場合(典型的な例)、このクラスはOpenCloseです。変更せずに新しいタイプの形状の面積を計算できます。次に、シェイプを描画する別のクラス、N個のシェイプを取り、より大きいシェイプを返す別のクラスがあります。一般に、シェイプを処理するシステム内の他のクラスは(少なくともシェイプについて)Open-Closeであると考えることができます。設計を見ると、工場はシステムの残りの部分を開閉でき、もちろん工場自体は開閉できません。
もちろん、何らかのファクトリーを動的にロードすることで、このファクトリーを開閉することもできます。システム全体を開閉することができます(例えば、クラスパスにいくつかのjarをドロップする新しい図形を追加できます)。あなたが評価する必要があるのは、この余分な複雑さは構築しているシステムに依存する価値があることです。すべてのシステムがプラグ可能な機能を必要とするわけではなく、すべてのシステムが完全に開閉する必要はありません。
それはすべて、どのように実装するかによって異なります。std::map
オブジェクトを作成する関数への関数ポインターを保持するために使用できます。その場合、オープン/クローズの原則に違反しません。またはスイッチ/ケース。
とにかく、ファクトリパターンが気に入らない場合は、常に依存性注入を使用できます。