🧩 Strategy × Template Method
✅ Combined Intent
- Use
Template Method
to define the fixed flow of a notification process - Delegate the variable part—the delivery method—to a
Strategy
This design centralizes a shared notification flow (e.g., logging, message formatting, pre/post-processing), while allowing the delivery mechanism (email, Slack, etc.) to be easily swapped through strategy injection.
✅ Common Use Cases
- When the overall process is consistent (e.g., logging or validation), but the way messages are delivered or formatted needs to be flexible
- When you want to send real emails in production but use mock notifications in testing
- When you want to reuse formatting logic or logging behavior across different types of notifications
✅ UML Class Diagram
✅ Code Example
- 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", "サーバー障害が発生しました")
✅ Explanation
Notifier
provides the shared template (logging, formatting, dispatching)formatMessage
is left abstract for subclasses likeAlertNotifier
to implement (Template Method)- The delivery strategy (
EmailStrategy
,SlackStrategy
) is injected, allowing dynamic switching (Strategy)
By fixing the overall process with a template and externalizing variable behavior as strategies, this design achieves both consistency and flexibility.
✅ Summary
- Template Method enforces a consistent flow for notifications
- Strategy decouples and enables flexible delivery behavior
- The design is extensible, testable, reusable, and easy to maintain