依存性注入
公開日: 2025/06/02
依存性注入とは?──結合度を下げて保守性とテスト性を高める設計技法
はじめに
クラスや関数の中で「他のモジュールを直接newして使う」と、その構造は強く結びつき、変更やテストが難しくなります。
こうした**“密結合”を解きほぐすためのテクニック**が「依存性注入(Dependency Injection:DI)」です。
本記事では、依存性注入の基本概念、利点、パターン、JavaScriptでの実装例、そしてDIコンテナの活用までを解説します。
基本情報・概要
依存性注入とは、オブジェクトの外部から必要な依存関係(インスタンスなど)を渡すことで、内部からの生成や依存を回避する設計パターンです。
主な目的:
- クラス間の結合度を下げる
- 実装の差し替え・モック化を容易にする
- テスト性・再利用性の向上
「依存を“持たせる”のではなく、“注入する”」という考え方です。
比較・分類・特徴の表形式まとめ(任意)
注入方法 | 説明 |
---|---|
コンストラクタ注入 | インスタンス生成時に依存を渡す(最も一般的) |
セッター注入 | メソッドやプロパティで後から依存を注入 |
インターフェース注入 | DIフレームワーク経由で明示的な注入を行う(TypeScriptなどで使用) |
依存性注入は**「誰が作るか」を分離することが本質**です。
深掘り解説
✅ JavaScript におけるコンストラクタ注入の例
class Logger { log(msg) { console.log(`[LOG] ${msg}`); } } class UserService { constructor(logger) { this.logger = logger; } createUser(name) { this.logger.log(`${name} を作成しました`); } } const logger = new Logger(); const userService = new UserService(logger); userService.createUser("田中"); // => [LOG] 田中 を作成しました
はUserService
を「自分で生成しない」Logger
- 代わりに「外から渡されたLogger」を使うことで、依存の切り離しとモック化が容易に
✅ テストのしやすさが段違い
class MockLogger { log(msg) { // テスト用に何もしない or 履歴に保存 } } const testLogger = new MockLogger(); const testService = new UserService(testLogger); testService.createUser("テストユーザー");
本物のLoggerではなくテスト用の依存に差し替えることで、単体テストが容易に。
応用・発展的な使い方
- DIコンテナの利用(TypeScript: tsyringe, inversify)
- 環境別依存の差し替え(開発/本番/テスト)
- プラグイン構造の実現:依存の注入で柔軟な機能追加を可能に
- モジュール単位での初期化制御(Factory + DI)
DIはオブジェクトの“つながり”を制御可能な構造にするための重要な技法です。
よくある誤解と注意点(任意)
- 「依存性注入=DIコンテナの使用」ではない:手動の注入でも十分DIである
- 小さな規模に導入しても効果が薄い場合がある:柔軟性とテスト性が必要な場面で真価を発揮
- 注入しすぎて構造が複雑化:依存の数と粒度に注意
- DIコンテナを乱用するとブラックボックス化:可視性とトレーサビリティが低下
DIは**制御の反転(IoC)**の一部でもあり、構造の透明性と責任分離が重要です。
まとめ
依存性注入は、設計の柔軟性とテスト性を高めるための強力なアプローチです。
「使う側」と「作る側」を分離することで、保守性の高いコードを実現し、環境に応じた挙動の差し替えも可能になります。
小さく導入し、徐々に構造を抽象化していくことで、DIの効果を自然に感じられるはずです。