🧩 DI パターン
✅ 設計意図
- 依存オブジェクトを内部で生成せず、外部から渡してもらう
- 「誰を使うか」を決める責務を外に出すことで柔軟性 UP
✅ 適用理由
- テスト時にモックやスタブに簡単に差し替え可能
- サービスの構成変更が実装を触らずにできる
✅ 向いているシーン
- DI コンテナが使えるアプリケーション構成
- クラスの依存関係を明示的に管理したいとき
✅ コード例
- TypeScript
- PHP
- Python
// インターフェースで依存先を抽象化(任意)
interface Notifier {
send(email: string, message: string): void;
}
// 実装クラス
class Mailer implements Notifier {
send(email: string, message: string): void {
console.log(`送信しました: ${email} → ${message}`);
}
}
// クライアントクラス
class UserService {
constructor(private notifier: Notifier) {}
registerUser(email: string): void {
console.log(`ユーザー登録: ${email}`);
this.notifier.send(email, "ようこそ!");
}
}
// 利用例(依存を注入)
const mailer = new Mailer();
const service = new UserService(mailer);
service.registerUser("user@example.com");
<?php
interface Notifier {
public function send(string $email, string $message): void;
}
class Mailer implements Notifier {
public function send(string $email, string $message): void {
echo "送信しました: {$email} → {$message}\n";
}
}
class UserService {
public function __construct(private Notifier $notifier) {}
public function registerUser(string $email): void {
echo "ユーザー登録: {$email}\n";
$this->notifier->send($email, "ようこそ!");
}
}
// 利用例(依存を注入)
$mailer = new Mailer();
$service = new UserService($mailer);
$service->registerUser("user@example.com");
from abc import ABC, abstractmethod
class Notifier(ABC):
@abstractmethod
def send(self, email: str, message: str):
pass
class Mailer(Notifier):
def send(self, email: str, message: str):
print(f"送信しました: {email} → {message}")
class UserService:
def __init__(self, notifier: Notifier):
self.notifier = notifier
def register_user(self, email: str):
print(f"ユーザー登録: {email}")
self.notifier.send(email, "ようこそ!")
# 利用例
mailer = Mailer()
service = UserService(mailer)
service.register_user("user@example.com")
✅ 解説
このコードは Dependency Injection (DI)
を使用して、UserService
が依存する Notifier
を外部から注入する設計を実現している。
DI
は、クラスが直接依存先を生成せず、外部から依存先を提供することで、疎結合を実現する設計パターン。
1. Dependency Injection の概要
- Interface: 依存先の共通インターフェースを定義し、依存先を抽象化。
- このコードでは
Notifier
が該当。
- このコードでは
- Concrete Implementation:
Interface
を実装した具体的な依存先。- このコードでは
Mailer
が該当。
- このコードでは
- Client:
Interface
に依存し、具体的な実装を外部から注入されるクラス。- このコードでは
UserService
が該当。
- このコードでは
2. 主なクラスとその役割
Notifier
- 依存先の共通インターフェース。
send(email: string, message: string): void
メソッドを定義。
Mailer
Notifier
を実装した具体的なクラス。- メール送信処理を実行。
UserService
- クライアントクラス。
- コンストラクタで
Notifier
を受け取り、ユーザー登録処理を行った後に通知を送信。
3. UML クラス図
4. Dependency Injection の利点
- 疎結合: クライアントクラス(
UserService
)が具体的な実装(Mailer
)に依存しないため、依存先を簡単に差し替え可能。 - テスト容易性: モックやスタブを注入することで、ユニットテストが容易になる。
- 拡張性: 新しい通知方法(例: SMS 通知)を追加する場合も、
Notifier
を実装するだけで対応可能。
この設計は、依存関係を外部から注入することで、コードの柔軟性と保守性を向上させる。特に、依存先が変更される可能性がある場合や、 テスト容易性を向上させたい場合に有効である。