🧩 Strategy Pattern
✅ Intent
- Allow dynamic selection of behavior by injecting interchangeable strategies
- Separate the "what changes" (format, logic, output) from "what stays the same" (execution flow)
✅ Motivation
- You want to switch between different behaviors like Email vs Slack notification
- You don’t want to hardcode
if
orswitch
logic every time you send a message
✅ When to Use
- Behavior needs to be configurable at runtime
- You need to test or reuse each variation independently
✅ Code Example
- TypeScript
- PHP
- Python
// Strategy インターフェース
interface NotificationStrategy {
send(user: string, message: string): void;
}
// Strategy 実装(メール)
class EmailStrategy implements NotificationStrategy {
send(user: string, message: string): void {
console.log("件名: お知らせ");
console.log(`本文: ${message}`);
console.log(`宛先: ${user}@example.com`);
}
}
// Strategy 実装(Slack)
class SlackStrategy implements NotificationStrategy {
send(user: string, message: string): void {
console.log(`Slack宛: ${user}`);
console.log(`内容: ${message}`);
}
}
// コンテキスト
class NotificationService {
constructor(private strategy: NotificationStrategy) {}
notify(user: string, message: string) {
this.strategy.send(user, message);
}
}
// 利用例
new NotificationService(new EmailStrategy()).notify(
"hiroshi",
"メールメッセージ"
);
new NotificationService(new SlackStrategy()).notify(
"hiroshi",
"Slackメッセージ"
);
<?php
interface NotificationStrategy {
public function send(string $user, string $message): void;
}
class EmailStrategy implements NotificationStrategy {
public function send(string $user, string $message): void {
echo "件名: お知らせ\n";
echo "本文: {$message}\n";
echo "宛先: {$user}@example.com\n";
}
}
class SlackStrategy implements NotificationStrategy {
public function send(string $user, string $message): void {
echo "Slack宛: {$user}\n";
echo "内容: {$message}\n";
}
}
class NotificationService {
public function __construct(private NotificationStrategy $strategy) {}
public function notify(string $user, string $message): void {
$this->strategy->send($user, $message);
}
}
// 利用例
(new NotificationService(new EmailStrategy()))->notify("hiroshi", "メールメッセージ");
(new NotificationService(new SlackStrategy()))->notify("hiroshi", "Slackメッセージ");
from abc import ABC, abstractmethod
class NotificationStrategy(ABC):
@abstractmethod
def send(self, user: str, message: str):
pass
class EmailStrategy(NotificationStrategy):
def send(self, user: str, message: str):
print("件名: お知らせ")
print(f"本文: {message}")
print(f"宛先: {user}@example.com")
class SlackStrategy(NotificationStrategy):
def send(self, user: str, message: str):
print(f"Slack宛: {user}")
print(f"内容: {message}")
class NotificationService:
def __init__(self, strategy: NotificationStrategy):
self.strategy = strategy
def notify(self, user: str, message: str):
self.strategy.send(user, message)
# 利用例
NotificationService(EmailStrategy()).notify("hiroshi", "メールメッセージ")
NotificationService(SlackStrategy()).notify("hiroshi", "Slackメッセージ")
✅ Explanation
This code uses the Strategy
pattern to encapsulate different notification methods (Email, Slack), and enables switching between them at runtime by injecting the strategy into a shared service.
The Strategy
pattern encapsulates a family of algorithms (in this case, notification methods), making them interchangeable without modifying the client logic.
1. Strategy Pattern Overview
-
Strategy: Defines a common interface for interchangeable behaviors
→NotificationStrategy
-
ConcreteStrategy: Implements different variants of the algorithm
→EmailStrategy
,SlackStrategy
-
Context: Uses the strategy and delegates behavior to it
→NotificationService
2. Key Classes and Responsibilities
-
NotificationStrategy
- Common interface for notification methods
- Method:
send(user: string, message: string): void
-
EmailStrategy
- Sends notification via Email
-
SlackStrategy
- Sends notification via Slack
-
NotificationService
- Uses a strategy object to perform notifications
- Strategy can be switched dynamically (e.g. for testing, config-based behavior, etc.)
3. UML Class Diagram
4. Benefits of the Strategy Pattern
- Runtime flexibility: Swap in new strategies without modifying client logic
- Open/Closed Principle: Add new notification formats without touching existing code
- Improved testability: Each strategy is isolated and easily mockable
This design solves the problem of hardcoded conditionals for variable behaviors. It enables you to inject variability while keeping the surrounding logic consistent and reusable.