Skip to content

Instantly share code, notes, and snippets.

@euske
Last active March 13, 2023 08:26
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save euske/75496e4d84455a7eb38284b29b034a0e to your computer and use it in GitHub Desktop.
Save euske/75496e4d84455a7eb38284b29b034a0e to your computer and use it in GitHub Desktop.
依存性逆転の原則 (Dependency Inversion Principle) と interface

依存性逆転の原則 (Dependency Inversion Principle) と interface

依存性逆転の原則とは

身近な例で考えてみよう。 あなたの会社は家庭用コンセントにつなぐ電気製品を開発している。 たまたま開発現場に Panasonic製のコンセントがあったので、 その差し込み口の寸法に合わせてプラグを設計した。 しかしこの方法には問題がある。Panasonic製のコンセントには ぴったり合っていたとしても、他社製のコンセントに対してはどうだろうか?

+----------+
|          |   依存
|   製品   +---------> [Panasonic製 コンセント]
|          |
+----------+

このような状態は、製品が「Panasonic製コンセント」という具体的な部品に 依存 (dependency) している状態である。これは望ましくない。 日本の家庭用コンセントは、 JIS C 8303 という規格で定義されている。したがって、本来は この規格に合わせて設計すべきなのである。

+----------+
|          |   依存
|   製品   +---------->  [JIS C 8303]
|          |                  ^
+----------+                  |
                              | 依存
                              |
        [Panasonic製コンセント]  [TOSHIBA製コンセント]

これが 依存性逆転の原則 (Dependency Inversion Principle) である。 ここでは、製品は (Panasonicという) 具体的なコンセントの実体ではなく、 抽象的な「規格」に依存している。 ここで「逆転」しているのは何かというと、いまや Panasonicのコンセントもこの規格に「依存」しているためである。 さらに Panasonic製だけでなく、TOSHIBA製のコンセントもこの規格に依存している。 抽象的な規格をもとに設計することで、この製品は どのメーカー製のコンセントにも対応できることになり、利用価値 (再利用性) が高められる。 プログラミングにおいては、このような「規格」のことを interface (インターフェイス) と呼ぶ。

依存注入 (Dependency Injection) における interface の重要性

依存性逆転の原則と interface は、先に解説した 依存注入 (Dependency Injection) を実現する際に重要である。 ブラウザをテストする例を思い出してほしい:

テスト時:

fakeInternet = 偽物のインターネット
display = browser(keyboard, mouse, fakeInternet)

本番時:

realInternet = 本物のインターネット
display = browser(keyboard, mouse, realInternet)

ここで、関数 browser は本物のインターネット realInternet と 偽物のインターネット fakeInternet のどちらも使えるようになっていなければならない。 もし関数 browser がどちらか一方のオブジェクト「だけ」に 合わせて設計されていたとすると、もう片方を切り換えて使うことはできない。 ここで出てくるのが依存性逆転の原則である。まず抽象的な規格 abstractInternet なるものを想定し、関数 browser を これに依存するように設計するのである:

+----------+
|          |   依存
| browser  +---------> [abstractInternet]
|          |                  ^
+----------+                  |
                              | 依存
                              |
                +------------+ +------------+
                |fakeInternet| |realInternet|
                +------------+ +------------+

ここで、さらに fakeInternetrealInternet のどちらも この規格に準拠するように設計しておけば、関数 browser はどちらの オブジェクトも同様に使えるようになり、依存注入が実現できる。

なお、ソフトウェア開発においては「規格に準拠する」という言葉は使わず 「interfaceを 実装する (implement)」という。

注意:

実際には、interface で規定できるものは非常に限られており、 これはただオブジェクトにつける目印のようなものにすぎない。 Java においては、interface を使うことで型チェックのエラーを防ぐことができる。 また、interface という用語は Java や C# での呼び方で、 Swift や Objective-C では protocol (プロトコル) と呼ばれている。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment