2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

依存性逆転とインターフェース設計の実際:DIの正体と誤解

Posted at

概要

「DI(Dependency Injection)」という言葉は流行しすぎたせいで、
単なるフレームワーク機能やコンストラクタ注入のことと誤解されがちである。

だがその本質は、依存性逆転の原則(DIP)にある。
これはアーキテクチャ上の制御の方向を反転させ、柔軟性とテスト性を確保する設計手法
である。

本稿では「依存性逆転」の真の意味を、インターフェース設計と実装の現場から掘り下げ、
DI=制御の抽象化であるという理解へ導く。


1. 依存性逆転原則(DIP)の原文

「高水準モジュールは低水準モジュールに依存すべきではない。両者は抽象に依存すべきである」

ここでのキーワードは 「抽象」「方向性」

  • 通常:上位が下位に依存する(使う側が使われる側に依存)
  • DIP:上位と下位を「抽象」で切り離し、疎結合にする

2. 実装レベルでの依存関係

class EmailService {
  send(message: string) {
    console.log("Sending email:", message)
  }
}

class UserNotifier {
  constructor(private emailService: EmailService) {}

  notify(user: string) {
    this.emailService.send(`Hello, ${user}`)
  }
}

UserNotifierEmailService にベタ依存 → DIP違反


3. 抽象で依存関係を反転させる

interface Notifier {
  send(message: string): void
}

class EmailService implements Notifier {
  send(message: string) {
    console.log("Email:", message)
  }
}

class UserNotifier {
  constructor(private notifier: Notifier) {}

  notify(user: string) {
    this.notifier.send(`Hello, ${user}`)
  }
}

UserNotifier は「何で通知するか」を知らない
依存するのは抽象(Notifier)だけ
→ 拡張性とテスト性が爆発的に向上する


4. Dependency Injectionの正体

DIとは、「依存を注入すること」ではない。
**「依存の選択と制御の責任を外部に移すこと」**である。

✅ 本質的な効果

  • 実装の差し替えが容易(Strategyとの相性が良い)
  • テストダブル(Stub, Mock)による検証が可能
  • 利用側が実装の詳細に一切依存しない

5. DIのバリエーション

タイプ 特徴
コンストラクタ注入 最も一般的、明示的でテスト容易
セッター注入 オプショナルな依存に有効
インターフェース注入 C#等で用いられる、フレームワーク依存のDI
フレームワークDI NestJSやSpringのような外部コンテナによる注入

→ 大事なのは「どの方式か」ではなく、設計の意図が守られているか


6. 現実的な設計判断フロー

① 上位モジュールが下位実装に依存していないか? → YES → DIP違反

② 実装の差し替え・テストダブルが容易か? → NO → インターフェースを導入

③ 拡張が既存コードに影響していないか? → YES → OCP違反+DIP不足

④ 「注入する」=「構造が壊れる」ではないか? → YES → 責務の分離ができていない

7. テスト観点でのDIの強み

class FakeNotifier implements Notifier {
  logs: string[] = []
  send(msg: string) { this.logs.push(msg) }
}

// テスト
const fake = new FakeNotifier()
const service = new UserNotifier(fake)

service.notify("Toto")
console.assert(fake.logs[0] === "Hello, Toto")

→ 実際のメール送信を伴わずに動作の確認が可能
外部依存なしで振る舞いを検証できる設計こそが本質


よくある誤解と対策

❌ 「DIフレームワークを使えばDIPを満たしている」

→ ✅ No。構造的依存が抽象に向いていなければ、フレームワークDIでもDIP違反


❌ 「インターフェースが多すぎると過剰設計」

→ ✅ 「差し替える可能性があるか?」という判断が先。将来的な柔軟性を設計するのがDIP


❌ 「DIは複雑になる」

→ ✅ 複雑なのは「責務の分離ができていないコード」。DIPは構造を整理する道具


結語

依存性逆転とは、
コードの制御権を低水準から高水準に戻し、拡張性と柔軟性を確保する設計戦略である。

  • 実装に依存せず、抽象に依存し
  • 依存の注入を通じて制御構造を外部化し
  • テスト可能で変更耐性のある構造を形成する

DIとは、
“設計を局所化し、柔軟性を外部に開くことで、コードを閉じたまま開発を進化させるための技法である。”

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?