Topiqlo ロゴ

依存性注入

公開日: 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の効果を自然に感じられるはずです。