🧩 Strategy × Template Method
✅ 組み合わせの意図
Template Method
で通知の流れ(テンプレート)を固定し、- 可変部分である通知手段を
Strategy
によって外部化する
共通の通知フロー(ログ出力・メッセージ整形・送信前後処理など)を一元化しながら、送信手段(メール、Slack など)だけを戦略的に差し替えられる設計。
✅ よく使われるシーン
- 処理手順は共通(ログや前処理など)だけど、送信方法や中身の戦略を柔軟に切り替えたいとき
- テスト環境では Mock 通知、本番ではメール通知など、通知先や形式を切り替えたいとき
- 通知テンプレートの整形や、送信ログの出力が共通化できるとき
✅ UML クラス図
✅ コード例
- TypeScript
- PHP
- Python
interface NotificationStrategy {
sendMessage(to: string, content: string): void;
}
class EmailStrategy implements NotificationStrategy {
sendMessage(to: string, content: string): void {
console.log(`[Email] To: ${to}, Message: ${content}`);
}
}
class SlackStrategy implements NotificationStrategy {
sendMessage(to: string, content: string): void {
console.log(`[Slack] To: ${to}, Message: ${content}`);
}
}
abstract class Notifier {
constructor(private strategy: NotificationStrategy) {}
send(user: string, message: string): void {
console.log("--- Sending Start ---");
const content = this.formatMessage(user, message);
this.strategy.sendMessage(user, content);
console.log("--- Sending End ---");
}
protected abstract formatMessage(user: string, message: string): string;
}
class AlertNotifier extends Notifier {
protected formatMessage(user: string, message: string): string {
return `[ALERT] ${user}: ${message}`;
}
}
// 使用例
const notifier = new AlertNotifier(new EmailStrategy());
notifier.send("taro@example.com", "サーバー障害が発生しました");
<?php
interface NotificationStrategy {
public function sendMessage(string $to, string $content): void;
}
class EmailStrategy implements NotificationStrategy {
public function sendMessage(string $to, string $content): void {
echo "[Email] To: {$to}, Message: {$content}\n";
}
}
class SlackStrategy implements NotificationStrategy {
public function sendMessage(string $to, string $content): void {
echo "[Slack] To: {$to}, Message: {$content}\n";
}
}
abstract class Notifier {
protected NotificationStrategy $strategy;
public function __construct(NotificationStrategy $strategy) {
$this->strategy = $strategy;
}
public function send(string $user, string $message): void {
echo "--- Sending Start ---\n";
$content = $this->formatMessage($user, $message);
$this->strategy->sendMessage($user, $content);
echo "--- Sending End ---\n";
}
abstract protected function formatMessage(string $user, string $message): string;
}
class AlertNotifier extends Notifier {
protected function formatMessage(string $user, string $message): string {
return "[ALERT] {$user}: {$message}";
}
}
// 使用例
$notifier = new AlertNotifier(new EmailStrategy());
$notifier->send("taro@example.com", "サーバー障害が発生しました");
from abc import ABC, abstractmethod
class NotificationStrategy(ABC):
@abstractmethod
def send_message(self, to: str, content: str) -> None:
pass
class EmailStrategy(NotificationStrategy):
def send_message(self, to: str, content: str) -> None:
print(f"[Email] To: {to}, Message: {content}")
class SlackStrategy(NotificationStrategy):
def send_message(self, to: str, content: str) -> None:
print(f"[Slack] To: {to}, Message: {content}")
class Notifier(ABC):
def __init__(self, strategy: NotificationStrategy) -> None:
self.strategy = strategy
def send(self, user: str, message: str) -> None:
print("--- Sending Start ---")
content = self.format_message(user, message)
self.strategy.send_message(user, content)
print("--- Sending End ---")
@abstractmethod
def format_message(self, user: str, message: str) -> str:
pass
class AlertNotifier(Notifier):
def format_message(self, user: str, message: str) -> str:
return f"[ALERT] {user}: {message}"
# 使用例
notifier = AlertNotifier(EmailStrategy())
notifier.send("taro@example.com", "サーバー障害が発生しました")
✅ 解説
Notifier
は共通のテンプレート処理を提供(ログ出力、整形、送信)formatMessage
の実装はサブクラス(例:AlertNotifier
)に任せる(Template Method
)- 送信戦略(
EmailStrategy
,SlackStrategy
)は注入可能で切り替え可能(Strategy
)
このように、処理のテンプレート(流れ)を固定しつつ、可変処理だけ戦略として外部化することで、 共通化と柔軟性のバランスが取れた設計になる。
✅ まとめ
- Template Method により、通知処理の一貫した流れを強制できる
- Strategy により、可変部分(送信手段)を自由に切り替えられる
- テスト・拡張・再利用・保守性に優れた設計