依存性逆転の原則

従来のレイヤーパターン

伝統的なアプリケーションアーキテクチャーにおいて、下位レベルコンポーネント（e.g. Utility Layer）はより複雑なシステムの構築を可能にする上位レベルコンポーネント（e.g. Policy Layer）によって使用される形で設計がおこなわれる。この方法では上位レベルコンポーネントは直接下位レベルコンポーネントに依存する。この低レベルコンポーネントへの依存は、上位レベルコンポーネントの再利用の機会を制限してしまう。
依存性逆転パターンの目指すところは、抽象レイヤーを導入することによってこの高度に結合した状態を回避し、上位の policy layer の再利用性を高めることにある。

依存性逆転パターン

抽象レイヤーを加える事により、上位レベルレイヤーと下位レベルレイヤーの両方とも top から bottom に向かう従来の依存関係を減らす事ができるが、"反転" の概念は下位レベルレイヤーが上位レベルレイヤーに依存することを意味しない。両方のレイヤーは上位レベルレイヤーが要求する振る舞いを表現した抽象に依存すべきである。
依存性逆転の直接のアプリケーションでは、抽象は上位/policy レイヤーによって所有される。このアーキテクチャーでは上位/policyコンポーネントと下位サービスを規定する抽象レイヤーを同一のパッケージとして扱う。低レベルレイヤーはこれらの抽象クラスやインターフェースを継承して生成される。
依存性とオーナーシップの逆転は上位/policyレイヤーの再利用性を高め、上位レイヤーは他の低レベルサービスを利用することができるようになる。もし低レベルレイヤーがクローズドなコンポーネントであったり、アプリケーションが既存のサービスを再利用する必要がある場合、サービスと抽象レイヤーの間を仲介するAdapterを設けるのが一般的である。

実装

DIPの２つの一般的な実装では、さまざまな意味でよく似た論理アーキテクチャを使用する。
直接的な実装において、 plicy クラスと service 抽象クラスは一つのライブラリーにパッケージ化される。この実装では上位コンポーネントと下位コンポーネントは別々のパッケージ/ライブラリとして配布される。上位レベルコンポーネントによって要求されるされる振る舞い/サービスを定義したインターフェースは上位レベルコンポーネントによって所有され、上位レベルコンポーネントと同じライブラリの中に存在する。 
上位レベルコンポーネントのインターフェースは下位レベルコンポーネントによって実装されるため、コンパイル時に下位レベルコンポーネントが上位レベルコンポーネントに依存する事が必要になる。よって従来の依存関係は逆転する。
Figures 1 and 2 では同じ機能を実現したコードを表現している。しかし、 Figure 2 ではインターフェースは依存性を逆転させるために使用されている。policy コードの再利用性を最大化したり、循環依存を排除するために依存の方向は選択することができる。
このバージョンの DIP では、下位レイヤーコンポーネントが上位レベルレイヤーのインターフェース/抽象に依存しているため、下位レベルレイヤーの再利用は困難になる。 この実装はその変わりに伝統的な to-to-bottom の依存関係を反対の bottom-to-top へと逆転させる。
抽象コンポーネントをライブラリやパッケージから独立させて置くと、より柔軟性が増す。
全てのレイヤーを分離して個別のパッケージに置くことでどのレイヤーの再利用性も向上し、ロバストネス性とモビリティーを得ることができる.

家系モジュール

ある家系システムでは人々の間の関係を第一レベル関係のグラフとして表現するかもしれません(父親/息子, 父親/娘, 母親/息子, 母親/娘, 夫/妻, 妻/夫...)。これは非常に効率的です(そして拡張も可能: 元夫/元妻, 法的保護者...)。
しかし、上位レベルモジュールでは家系をブラウズするためのより簡単な方法が必要になるかもしれません: 人には、子供、父親、母親、兄弟と姉妹(異母兄弟を含む含まないも合わせて）、祖父、祖母、伯父、伯母、従兄弟... などがいるかもしれません。
家系モジュールの使用法に応じて、共通の関係を明確で直接的な属性として（グラフを隠して）表示することは上位レベルモジュールと家系モジュールの間の結合を遥かに軽くでき、モジュールの使用になんの影響も与えることなく内部表現を完全に変更することを可能にします。またそれによって、家系モジュールに対し兄弟、姉妹（異母兄弟であるかどうか）の正確な定義を埋め込む事が可能になります... またそれは単一責務の法則を強制することにも繋がります。
最終的に、もし最初の一般化された拡張可能なグラフアプローチが一番拡張可能に思えるのであれば、家系モジュールの利用は更に特殊化及び単純化された関係の実装がアプリケーションに対して十分であることを示しているかもしれませんし、より効率的なシステムを作成する手助けになるかもしれません。
この例でのモジュール間の相互関係の抽象化は下位レベルモジュールのインターフェースの単純化だけでなく、より単純化された実装につながるかもしれません。

Model View Controller

UI とアプリケーションレイヤーパッケージは主に具象クラスを含んでいて、コントローラーは抽象/インターフェース型を含んでいます。また UI は ICustomerHandler のインスタンスを保持し、全てのパッケージは物理的に分離されていて。アプリケーションレイヤーには Page クラスが使用する具象クラスの実装が存在しています。これらのインターフェースのインスタンスは （コントローラーと同じパッケージに存在するかもしれない）Factory によって動的に生成されます。具象タイプである Page と CustomerHandler はお互いに依存してはらなず、両方とも ICustomerHandler に依存します。 
これらの直接的な効果は、UI が直接 ApplicatonLayer や、ICustomerHandler を実装したどの具象パッケージも参照する必要がない事です。コンクリートクラスはリフレクションを使用してロードされます。またどの時点であっても、具象実装は UI クラスに変更を及ぼさずに他の具象実装に差し替える事ができます。他の興味深い可能性は Page クラスが ICustomerHander のメソッドに引数として渡す事ができるインターフェース IPageViewer を実装していると言う事で、これによってt具象実装は具象的な依存なしに UI と通信する事ができます。何故なら両者はインターフェースでリンクされているからです。

関連するパターン

依存性逆転の原則の適用はアダプターパターンの一例と見ることもできます。例えば、上位レベルクラスが自身が依存する抽象への固有のアダプターインターフェースを定義するような場合がそれに当たります。アダプティーの実装はまたアダプターインターフェスに依存しますが（もちろん、このインターフェースを実装しているので）独自の下位レベルモジュール内のコードを用いて実装を行うこともできます。上位レベルモジュールは、アダプティーとその下位レベルモジュールによって実装されたインターフェースへのポリモーフィックな関数を呼び出すことによってアダプターインターフェースを介して間接的に下位レベルモジュールを利用するため、上位レベルモジュールが下位レベルモジュールに依存するといったことはありません。
Plugin, Service Locator, or Dependency Injection などの様々なパターンは上位レベルコンポーネントに対する選択された下位レベルコンポーネントの "run-time provisioning" を容易にする目的で導入されます。

History

The dependency inversion principle was postulated by Robert C. Martin and described in several publications including the paper Object Oriented Design Quality Metrics: an analysis of dependencies, an article appearing in the C++ Report in May 1996 entitled The Dependency Inversion Principle, and the books Agile Software Development, Principles, Patterns, and Practices, and Agile Principles, Patterns, and Practices in C#.