ソフトウエアモジュールを疎結合に保つための特定の形式を指す用語。この原則に従うとソフトウェアの振る舞いを定義する上位レベルのモジュールから下位レベルモジュールへの従来の依存関係は逆転し、結果として下位レベルモジュールの実装の詳細から上位レベルモジュールを独立に保つことができるようになる。上位レベルのモジュールは下位レベルのモジュールに依存すべきではない。両方とも抽象(abstractions)に依存すべきである。抽象は詳細に依存してはならない。詳細が抽象に依存すべきである。この上位レベル、下位レベルの両方とも抽象に依存しなければならないと言う要求により、この設計原理は一部の人々のオブジェクト指向プログラミングに対する考え方を反転させる。背景にある考えは、上位モジュールと下位モジュールの相互作用を設計する際に、これらの関係が抽象的な相互作用として捉えられるべきであるということであり、これによって上位モジュールだけでなく下位レベルモジュールも設計的な影響を受けることになる。下位モジュールは相互作用を念頭に設計されるべきで、その結果自身を使用するためのインターフェースについて変更を行う必要が生じる可能性がある。多くの場合、相互作用を抽象的な概念として捉えることにより追加のコーディングパターンを導入せずにコンポーネント間の結合を減らすことができ、より軽量で実装への依存が少ない総合作用スキーマを用いるだけで済むようになる。2つのモジュールの間で見出された抽象的な相互関係が一般性を持ち、かつ一般化が意味を持つとき、この設計原理は以下の依存性の逆転コーディングパターンを導く。Layer)によって使用される形で設計がおこなわれる。この方法では上位レベルコンポーネントは直接下位レベルコンポーネントに依存する。この低レベルコンポーネントへの依存は、上位レベルコンポーネントの再利用の機会を制限してしまう。再利用性を高めることにある。概念は下位レベルレイヤーが上位レベルレイヤーに依存することを意味しない。両方のレイヤーは上位レベルレイヤーが要求する振る舞いを表現した抽象に依存すべきである。レイヤーによって所有される。このアーキテクチャーでは上位/policyコンポーネントと下位サービスを規定する抽象レイヤーを同一のパッケージとして扱う。低レベルレイヤーはこれらの抽象クラスやインターフェースを継承して生成される。[2]依存性とオーナーシップの逆転は上位/policyレイヤーの再利用性を高め、上位レイヤーは他の低レベルサービスを利用することができるようになる。低レベルレイヤーがクローズドなコンポーネントであったり、アプリケーションが既存のサービスを再利用する必要がある場合、サービスと抽象レイヤーの間を仲介するAdapterを設けるのが一般的である。依存性逆転パターンの一般化[編集]多くのプロジェクトにおいて依存性逆転の原則とパターンは一般化されるべき概念であると考えられる。これには少なくとも以下の2つの理由がある。優れた考えの原則をコーディングパターンとみなすほうがよりシンプルである。ひとたび抽象クラスやインターフェースが実装されるとプログラマーは「自分は抽象化のための仕事をした」と言うかもしれない。多くのユニットテストツールがモックを作成するためにインターフェースに依存しているため、クラス間のジェネリックなインターフェースを利用することは(モジュール間に限った話ではなく一般的にも)ルールになっている。インターフェースのみに依存するモック作成ツールを使用している場合、一般化された依存性逆転パターンが必要になることがあるが、これには大きな欠点がある。クラスに対して単純にインターフェースを実装するだけでは不十分であり、一般的に結合を減らすことにはならない。相互作用に対しての潜在的な抽象化を考える事が唯一結合を減らす設計につながり得る。ジェネリックなインターフェースをプロジェクト内の全ての箇所で実装してしまうと、理解してメンテナンスをするのが非常に難しくなる。ソースコードを読む人は全てのステップにおいて「このインターフェースの他の実装はなんだろうか」と自問することになり、そしてその答えはほとんど「モックだけ」ということになりかねない。ある事が要求され、一般的に依存性注入フレームワークに依存するファクトリーなどが特にそれにあたる。インターフェースの一般化はプログラミング言語の利用も制限する。一般化における制約[編集]依存性逆転のパターン(DIP)を達成するためにインターフェースが存在することは、オブジェクト指向プログラムにおいて他の設計上の制約をもたらす:クラス内の全てのメンバー変数はインターフェース、もしくは抽象でなくてはならない。全ての具象クラスパッケージはインターフェース、もしくは抽象クラスパッケージを通してのみ結合されなければならない。具象クラスを派生してはならない。実装済みのメソッドをオーバーライドしてはならない。パターン(英語版)のような生成に関するパターン(英語版)の実装が必要になる。DIフレームワークが必要になる。インターフェースモック化の制約[編集]継承ベースのモック化ツールを使用した場合でも以下の制約が生じる。外部公開されている静的メンバーも体系的に依存性性注入されるべきだが、そのための実装はかなり難しい。テスト可能な全てのモジュールはインターフェースの実装、もしくは抽象定義のオーバーライドを行う必要がある。将来的な方向性[編集]原則は考えるための方法であり、パターンは問題解決のための共通手段である。コーディングパターンはプログラミング言語に欠如している機能であるとみなされるかもしれない。プログラミング言語は少なくとも2つの方向で、その使用においてより正確に、より強力になる方向に進化を続けるだろう。ひとつは使用条件の強化(事前、事後、そして不変条件)、もう一つは状態ベースのインターフェースである。これらは多くの状況において、より強力な依存性逆転の応用の促進し、潜在的に単純化に寄与するだろう。静的メンバーや非仮想メンバーの置き換えの問題を解決するために、今やより多くのモック化ツールがコード注入を用いるようになっている。バイトコードを生成するように今後進化するかもしれない。一つの方向性は非仮想メンバーの使用を制限するというもの。一つは、少なくともテストを行う状況においては、非継承ベースのモック化が可能なバイトコードを生成するというものだ。実装[編集]DIPの2つの一般的な実装では、さまざまな意味でよく似た論理アーキテクチャを使用する。抽象クラスは一つのライブラリーにパッケージ化される。この実装では上位コンポーネントと下位コンポーネントは別々のパッケージ/ライブラリとして配布される。上位レベルコンポーネントによって要求されるされる振る舞い/サービスを定義したインターフェースは上位レベルコンポーネントによって所有され、上位レベルコンポーネントと同じライブラリの中に存在する。上位レベルコンポーネントのインターフェースは下位レベルコンポーネントによって実装されるため、コンパイル時に下位レベルコンポーネントが上位レベルコンポーネントに依存する事が必要になる。よって従来の依存関係は逆転する。同じ機能を実現したコードを表現している。インターフェースは依存性を逆転させるために使用されている。コードの再利用性を最大化したり、循環依存を排除するために依存の方向は選択することができる。下位レイヤーコンポーネントが上位レベルレイヤーのインターフェース/抽象に依存しているため、下位レベルレイヤーの再利用は困難になる。抽象コンポーネントをライブラリやパッケージから独立させて置くと、より柔軟性が増す。