先日実装したAPI呼び出し(Repository)部分の実装をしたときに、レビューでDIに関する指摘をもらったので、これを機にDIについてまとめておきます。
概要
DIとは、Dependency Injection
の略で、日本語で言うと、依存性注入
になります。
DIに何のメリットがあるかは、百聞は一見にしかずなので、まずはTypeScriptでゴルフクラブに例えて説明してみたいと思います。
例
ゴルフクラブは、ヘッドやシャフト、グリップ等から成り立って(=依存)いますが、今回は簡略化して、ヘッドのみとして例えてみます。
DIしないパターン
class Head {
getHeadName(headName: string) {
return headName;
}
}
class GolfClub {
swing(): string {
const head = new Head();
const headName = head.getHeadName("Stelth")
return `ヘッドは${headName}を使ってスウィングしました`
}
}
const golfClub = new GolfClub();
console.log(golfClub.swing());
//[LOG]: "ヘッドはStelthでスウィングしました。"
DIしないパターンの特徴は、GolfClubクラスのswingメソッド内で、Headクラスのインスタンスを生成している点です。
このコードには欠点があり、たとえば、ヘッドはStelth
ですが、PARADYM
に変えたくなったら、また違うクラスを作らないといけません。
DIしたパターン
次にDIした場合はというと、
class GolfClub {
head: Head
constructor(head: Head) {
this.head = head
}
swing(headName: string): string {
return `ヘッドは${this.head.getHeadName(headName)}でスウィングしました。`
}
}
class Head {
getHeadName(headName: string) {
return headName
}
}
const head = new Head()
const club = new GolfClub(head);
console.log(club.swing("Paradyme"));
この場合の特徴としては、HeadクラスのインスタンスはGolfClub
の外部からコンストラクタの引数として受け取っており、GolfClub
は自らで各パーツのインスタンスを生成する責任は無くなりました。(constructor injection)
このように、GolfClub内部で必要な(依存)インスタンスを生成するのではなく、外部からconstructorの引数に渡す(注入)ので、依存性注入と呼ばれています。
DIのメリット
上記の例で分かる通り、(極端な例ではありますが、)
DIしたほうが汎用性が高くなることが分かるかと思います。
また、クラス間の結合も疎にできるので、各クラスの変更にも強くなります。
疎結合になるということは、各クラスの単体テスト性の向上も見込めます。