web-dev-qa-db-ja.com

オープンクローズの原則(OCP)と依存関係の逆転の原則(DIP)

Open Closed Principle (OCP)と Dependency Inversion Princible (DIP)の違いを理解しようとしていました。

これまでにインターネットで行った調査に基づいて、「DIPはOCPを達成するための1つのオプションである」という結論に達しました。

私はこれで正しいですか?

DIPではなくOCPに従う例を教えていただけますか?

12
Jitendar

私は以前に回答を書いた Open-Closed Principle(OCP)vs Liskov's Substitution Principle(LSP) 両方の原則は互いにかなり関連していますが、まだ概念的に異なり、1つのしかし、他ではありません。この回答のため、OCPについて簡単に触れ、DIPとその理由について詳しく説明します。

OCPがどのように関係し、依存関係の逆転の原理(DIP)と異なるのかを最初に異なる原理を説明することによって議論してみましょう。

依存関係の逆転の原則

読む ボブおじさんのOODの原則 DIPは次のよ​​うに述べていることがわかります。

具象ではなく、抽象化に依存します。

Java=の抽象化は、interfaceおよびabstractキーワードを使用して簡単に実現できます。つまり、コードが従わなければならないソフトウェアエンティティの「契約」があることを意味します。一部のプログラミング言語には、コードが従うべき動作を明示的に設定する機能がないため、コンパイラーにコントラクトを強制させるのではなく、より手動で抽象化に従う必要があります。たとえば、C++では、仮想メソッドを持つクラスがあり、 Javascriptなどの動的プログラミング言語では、オブジェクトを同じ方法で使用する必要があります(Javascriptの場合、これはTypeScriptで拡張され、コンパイラによって検証されるコントラクトの記述を支援する型システムを追加します)。

名前には「反転」という用語が含まれています。これは、伝統的に(プログラミングの古い暗黒時代に知っています)、低レベルのモジュールに応じて高レベルのモジュールを持つソフトウェア構造を作成したためです。例えば。 KitchenLamp1KitchenLamp2の入力を処理するButtonAtKitchenを持つことは理にかなっています。残念ながら、これによりソフトウェアは必要以上に具体的になり、オブジェクトグラフは次のようになります。

ButtonAtKitchen handles KitchenLamp1 and KitchenLamp2

したがって、ソフトウェアをより一般的なものにするには、「契約」を追加します。オブジェクトグラフの矢印が方向を「反転」させていることに注目してください。そのキッチンランプはButtonに依存しています。つまり、詳細は逆ではなく抽象化に依存するようになりました。

KitchenButton now has a IButton abstraction that the kitchen lamps are dependent on

したがって、私たちはDIPのより一般的な定義を持っています。これは ncle BobによるDIPの元の記事 でも詳しく説明されています。

A.高レベルモジュールは低レベルモジュールに依存しないでください。どちらも抽象化に依存する必要があります。 B.抽象化は詳細に依存すべきではありません。詳細は抽象化に依存する必要があります。

開閉原理

ボブおじさんの原則に続き、OCPは次のよ​​うに述べていることがわかります。

クラスの動作を変更せずに拡張できるはずです。

これを達成する1つの例は、 戦略パターン を使用することです。ここで、Contextクラスは変更のために閉じられています(つまり、変更できません)これは内部コードですが)コラボレーションの依存関係(つまり、戦略クラス)を通じて拡張のために開かれています

より一般的な意味では、どのモジュールも拡張ポイントを介して拡張できるように構築されています。

A module with extension points

OCPはDIPに似ていますよね?

いいえ、そうではありません。

どちらも抽象化について議論していますが、概念的には異なります。どちらの原則も、1つの特定のモジュールでのOCPと複数のモジュールでのDIPの異なるコンテキストに注目しています。ほとんどのGang of Fourデザインパターンと同じように両方を同時に実現できますが、それでもパスから離れることができます。

上記のDIPの例では、ボタンとキッチンランプの場合、キッチンランプはどれも拡張可能ではありません(現在、拡張する必要があることを説明する要件はありません)。設計はOCPを破っていますが、DIPに従います。

逆の(そして工夫された)例は、キッチンランプが拡張可能であることです(拡張ポイントはLampShadeのようなものです)が、ボタンはランプに依存していますbreaking DIPですが、OCPに従います。

心配しないで、それは起こります

これは実際には、プロダクションコードで頻繁に発生するものであり、その一部が原則を破る可能性があります。より大きなソフトウェアシステム(つまり、上記の例よりも大きいもの)では、コードを単純に保つ必要があるため、1つの原則を破るが、通常は他の原則を維持する場合があります。私の考えでは、単一の責任の原則(SRP)に関連しているため、小型で自己完結型のモジュールには問題ありません。

いったんいくつかのモジュールが複雑になったとしても、すべての原則を念頭に置いてそれを見て再設計するか、 refactor をよく知られたパターンに変更する必要があります。

16
Spoike