🧩 Strategy パターン
✅ 設計意図
- 振る舞い(戦略)を外部から差し替え可能にすることで、処理の柔軟性を高める
- 呼び出し側が、共通処理の「可変部分」を注入して選べるようにする
✅ 適用理由
- 通知内容やフォーマットの切り替えを動的に制御したい
- パターンごとの再利用性・テスト性を高めたい
✅ 向いているシーン
- 処理の切り替えが頻繁、もしくは構成によって振る舞いを変えたい場合
✅ コード例
- 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メッセージ")
✅ 解説
このコードは Strategy
パターン を使用して、通知方法(メールや Slack)を動的に切り替えられる設計を実現している。
Strategy
パターンは、アルゴリズムや処理をクラスとして分離し、動的に切り替え可能にするデザインパターン。
1. Strategy パターンの概要
- Strategy: 共通のインターフェースを定義し、異なるアルゴリズムを統一的に扱う
- このコードでは
NotificationStrategy
が該当
- このコードでは
- ConcreteStrategy:
Strategy
を実装し、具体的なアルゴリズムを提供する- このコードでは
EmailStrategy
とSlackStrategy
が該当
- このコードでは
- Context:
Strategy
を利用するクラスで、具体的なアルゴリズムを動的に切り替える- このコードでは
NotificationService
が該当
- このコードでは
2. 主なクラスとその役割
NotificationStrategy
- 通知方法の共通インターフェース
send(user: string, message: string): void
メソッドを定義
EmailStrategy
NotificationStrategy
を実装した具体的な戦略クラス- メール形式で通知を送信
SlackStrategy
NotificationStrategy
を実装した具体的な戦略クラス- Slack 形式で通知を送信
NotificationService
Context
クラス- コンストラクタで
NotificationStrategy
を受け取り、notify
メソッドで現在の戦略に応じた通知を送信
3. UML クラス図
4. Strategy パターンの利点
- 柔軟性: 戦略を動的に切り替えることで、異なる処理を簡単に適用可能
- 単一責任の原則: 各戦略が独立したクラスに分離されており、保守性が高い
- 拡張性: 新しい通知方法を追加する場合も、
NotificationStrategy
を実装するだけで対応可能
この設計は、アルゴリズムや処理を柔軟に切り替える必要がある場面で非常に有効であり、コードの拡張性と保守性を向上させる。