アレがアレでアレ

(できれば)プログラミング関係のことを書きたい

依存関係逆転の原則

SOLID原則の1つである、依存関係逆転の原則について簡単にまとめたものです。

※依存性の注入に関してここでは解説しません。

依存関係逆転の原則とは

定義

  1. 上位のモジュールは下位のモジュールに依存してはならない。どちらのモジュールも「抽象」に依存すべきである。
  2. 「抽象」は実装の詳細に依存してはならない。実装の詳細が「抽象」に依存すべきである。

引用元: Robert C. Martin. アジャイルソフトウェア開発の奥義

これだけだとちょっとなにを言ってるのかよくわかりませんね。
簡単に言うと、変更されやすく、脆いモジュールへの依存しているものを、変更されにくいものへ依存するようにしなさいという原則です。

変更されやすいものに依存している例

本を扱うシステムがあり、その中に以下のようなモジュールがあるとします。

f:id:eiken7kyuu:20200811170007p:plain

これは、本のタイトルを入力すると本検索APIを呼び出し、本情報を取得、結果をユーザーに返すモジュールです。
上位レベルServiceレイヤ内のBookServiceは検索結果を取得するために、下位レベルInfrastructureレイヤにあるBookSearchApiクラスを利用しています。

システムはこのように制御の流れ依存の流れが同じになってしまいがちです。
アプリケーションの方針を決めている上位レベルのモジュールが、実装の詳細を担当している下位レベルのモジュールに依存してしまっています。

上位レベルと比べて下位レベルのモジュールは脆く、変更されやすいものです。
この依存によって、下位レベルのモジュールの変更が上位レベルのモジュールにまで影響するようになっています。

そこで依存関係逆転の原則を使って、下位レベルのモジュールを上位レベルのモジュールに依存させ、依存関係を逆転させます。

依存を逆転させたあと

依存関係を逆転させた後の図が以下になります。

f:id:eiken7kyuu:20200811172843p:plain

ServiceレイヤでIBookSearchApiインターフェースを宣言し、InfrastructureレイヤのBookSearchApiはこのインターフェースを実装するようにします。

こうすることでBookServiceは同じレイヤにある「抽象」を通してBookSearchApiを利用するようになり、上位モジュールが下位モジュールに依存しなくなりました。
逆に、上位の「抽象」に下位レベルの実装の詳細が依存していることになります。
つまり、下位レベルを変更しても上位レベルがその影響を受けなくなります。

実装の詳細に依存せず、抽象に依存する。これが依存関係逆転の原則です。

所有権も逆転

クライアント側がインターフェースを所有しているので「依存」だけでなく「所有権」も逆転しています。
Infrastructureレイヤの影響を受けないだけでなく、IBookSearchApiを実装するものであれば何でも再利用できるようになっています。

例えば元々、楽天ブックス書籍検索APIを使って実装していたものをGoogle Books APIsへ変更することも楽になりました。

標準ライブラリとかはどうするの?

実装の詳細に依存するな。ですが、例えばC#のstringクラスはどうするのか?

こういったクラスは安定しているので依存しても問題ありません。
依存関係逆転の原則を考えるときはOSやプラットフォーム周りは気にせず、システム内の変化しやすい詳細にのみ気をつければ良いそうです。

まとめ

  • 変化しやすい実装の詳細に依存するな。抽象に依存しよう。

参考