依存性逆転の原理とは何ですか?なぜそれが重要なのですか?質問する

依存性逆転の原理とは何ですか?なぜそれが重要なのですか?質問する

依存性逆転の原則とは何ですか? また、なぜそれが重要なのですか?

ベストアンサー1

それは何ですか?

依存性逆転の原則の本来の目的と動機を完全に理解するには、書籍『Agile Software Development, Principles, Patterns, and Practices』および『Agile Principles, Patterns, and Practices in C#』が最適なリソースです。記事「依存性逆転の原則」も優れたリソースですが、これは最終的に前述の書籍に収録された草稿の要約版であるため、パッケージとインターフェイスの所有権の概念に関する重要な説明が抜けています。この概念は、この原則を、書籍『Design Patterns』(Gamma 他) に記載されている「実装ではなくインターフェイスにプログラムする」というより一般的なアドバイスと区別する上で重要です。

要約すると、依存性逆転の原則は、主に「上位レベル」のコンポーネントから「下位レベル」のコンポーネントへの従来の依存性の方向を逆転させ、「下位レベル」のコンポーネントが「上位レベル」のコンポーネントが所有するインターフェースに依存するようにすることです。(注: ここでの「上位レベル」のコンポーネントは、外部の依存性/サービスを必要とするコンポーネントを指し、必ずしも階層化アーキテクチャ内の概念的な位置を指すわけではありません。) そうすることで、結合はそれほど削減されるのではなく、理論的に価値の低いコンポーネントから理論的に価値の高いコンポーネントに移行されます。

これは、コンポーネントの消費者が実装を提供する必要があるインターフェイスの観点から外部依存関係が表現されるコンポーネントを設計することによって実現されます。言い換えると、定義されたインターフェイスは、コンポーネントの使用方法ではなく、コンポーネントに必要なものを表現します (例: 「IDoSomething」ではなく「INeedSomething」)。

依存性逆転の原則が言及していないのは、インターフェースの使用を通じて依存性を抽象化する単純な方法です (例: MyService → [ILogger ⇐ Logger])。これにより、コンポーネントは依存性の特定の実装の詳細から切り離されますが、コンシューマーと依存性の関係は逆転しません (例: [MyService → IMyServiceLogger] ⇐ Logger)。

どうしてそれが重要ですか?

依存性逆転の原則の重要性は、機能の一部 (ログ記録、検証など) で外部依存関係に依存するソフトウェア コンポーネントを再利用できるようにするという単一の目標に要約できます。

再利用のこの一般的な目標の範囲内で、再利用の 2 つのサブタイプを区別することができます。

  1. サブ依存関係の実装を持つ複数のアプリケーション内でソフトウェア コンポーネントを使用する (例: DI コンテナーを開発し、ログ記録を提供したいが、コンテナーを特定のロガーに結合して、コンテナーを使用するすべてのユーザーが選択したログ記録ライブラリも使用しなければならないようにしたくない)。

  2. 進化するコンテキスト内でのソフトウェア コンポーネントの使用 (例: 実装の詳細が進化するアプリケーションの複数のバージョンにわたって同じままのビジネス ロジック コンポーネントを開発した場合)。

インフラストラクチャ ライブラリなど、複数のアプリケーション間でコンポーネントを再利用する最初のケースでは、その目標は、独自のライブラリのサブ依存関係に消費者を結合せずに、消費者にコア インフラストラクチャのニーズを提供することです。これは、そのような依存関係に結合すると、消費者にも同じ依存関係が必要になるためです。これは、ライブラリの消費者が同じインフラストラクチャのニーズに対して別のライブラリを使用することを選択した場合 (例: NLog と log4net)、または必要なライブラリの新しいバージョンを使用することを選択した場合に問題になる可能性があります。このライブラリのバージョンは、ライブラリに必要なバージョンと下位互換性がありません。

ビジネス ロジック コンポーネント (つまり、「高レベル コンポーネント」) を再利用する 2 番目のケースでは、アプリケーションのコア ドメイン実装を、実装の詳細 (つまり、永続性ライブラリ、メッセージング ライブラリ、暗号化戦略などの変更/アップグレード) の変更ニーズから分離することが目標です。理想的には、アプリケーションの実装の詳細を変更しても、アプリケーションのビジネス ロジックをカプセル化するコンポーネントが壊れることはありません。

注: 2 番目のケースを実際の再利用として説明することに反対する人もいるかもしれません。これは、単一の進化するアプリケーション内で使用されるビジネス ロジック コンポーネントなどのコンポーネントは、1 つの使用のみを表すという理由からです。ただし、ここでの考え方は、アプリケーションの実装の詳細を変更するたびに新しいコンテキストが生成され、したがって異なる使用ケースが生成されるというものです。ただし、最終的な目標は、分離と移植性として区別できます。

この 2 番目のケースで依存性逆転の原則に従うと、ある程度のメリットが得られますが、Java や C# などの最新言語に適用した場合の価値は大幅に低下し、おそらくは無関係になる点に留意する必要があります。前述のように、DIP では実装の詳細を別々のパッケージに完全に分離します。ただし、進化するアプリケーションの場合は、ビジネス ドメインの観点から定義されたインターフェイスを使用するだけで、実装の詳細コンポーネントのニーズの変化によって高レベルのコンポーネントを変更する必要がなくなります。これは、実装の詳細が最終的に同じパッケージ内に存在する場合でも同じです。この原則の部分は、原則が成文化されたときの言語 (つまり C++) に関連し、新しい言語には関連しない側面を反映しています。とはいえ、依存性逆転の原則の重要性は、主に再利用可能なソフトウェア コンポーネント/ライブラリの開発にあります。

この原則について、インターフェースの単純な使用、依存性の注入、および分離されたインターフェース パターンに関連する詳細な説明は、ここ にあります。また、この原則が JavaScript などの動的型付け言語とどのように関連するかについての説明は、ここ にあります。

おすすめ記事