🧩 Template Method パターン
✅ 設計意図
- 処理全体のテンプレート(流れ)を定義し、一部の処理をサブクラスに委ねる
- ベタ書きされていた変化点のみを明示的に抽象化
✅ 適用理由
- 通知の構成(送信先・本文など)の共通部分を明確にしつつ、差分だけを分けたい
- 処理の流れが固定されているが、一部を柔軟に変えたいときに最適
✅ 向いているシーン
- 処理手順が共通していて、特定ステップだけ異なるケース
- 初期化・実行・終了などの「型」がある処理
✅ コード例
- TypeScript
- PHP
- Python
abstract class Notifier {
send(user: string, message: string) {
console.log(this.header());
console.log(this.formatMessage(message));
console.log(this.destination(user));
}
protected abstract header(): string;
protected abstract destination(user: string): string;
protected abstract formatMessage(message: string): string;
}
class EmailNotifier extends Notifier {
protected header(): string {
return "件名: お知らせ";
}
protected destination(user: string): string {
return `宛先: ${user}@example.com`;
}
protected formatMessage(message: string): string {
return `本文: ${message}`;
}
}
class SlackNotifier extends Notifier {
protected header(): string {
return "Slack 通知";
}
protected destination(user: string): string {
return `Slack宛: ${user}`;
}
protected formatMessage(message: string): string {
return `内容: ${message}`;
}
}
// 利用例
new EmailNotifier().send("hiroshi", "メールメッセージ");
new SlackNotifier().send("hiroshi", "Slackメッセージ");
<?php
abstract class Notifier {
public function send(string $user, string $message): void {
echo $this->header() . "\n";
echo $this->formatMessage($message) . "\n";
echo $this->destination($user) . "\n";
}
abstract protected function header(): string;
abstract protected function destination(string $user): string;
abstract protected function formatMessage(string $message): string;
}
class EmailNotifier extends Notifier {
protected function header(): string {
return "件名: お知らせ";
}
protected function destination(string $user): string {
return "宛先: {$user}@example.com";
}
protected function formatMessage(string $message): string {
return "本文: {$message}";
}
}
class SlackNotifier extends Notifier {
protected function header(): string {
return "Slack 通知";
}
protected function destination(string $user): string {
return "Slack宛: {$user}";
}
protected function formatMessage(string $message): string {
return "内容: {$message}";
}
}
// 利用例
(new EmailNotifier())->send("hiroshi", "メールメッセージ");
(new SlackNotifier())->send("hiroshi", "Slackメッセージ");
from abc import ABC, abstractmethod
class Notifier(ABC):
def send(self, user: str, message: str):
print(self.header())
print(self.format_message(message))
print(self.destination(user))
@abstractmethod
def header(self) -> str: pass
@abstractmethod
def destination(self, user: str) -> str: pass
@abstractmethod
def format_message(self, message: str) -> str: pass
class EmailNotifier(Notifier):
def header(self) -> str:
return "件名: お知らせ"
def destination(self, user: str) -> str:
return f"宛先: {user}@example.com"
def format_message(self, message: str) -> str:
return f"本文: {message}"
class SlackNotifier(Notifier):
def header(self) -> str:
return "Slack 通知"
def destination(self, user: str) -> str:
return f"Slack宛: {user}"
def format_message(self, message: str) -> str:
return f"内容: {message}"
# 利用例
EmailNotifier().send("hiroshi", "メールメッセージ")
SlackNotifier().send("hiroshi", "Slackメッセージ")
✅ 解説
このコードは Template Method
パターン を使用して、通知処理の共通フローを抽象クラス(Notifier
)で定義し、
具体的な処理(メール通知や Slack 通知)をサブクラスで実装する設計を実現している。
Template Method
パターンは、アルゴリズムの骨組みをスーパークラスで定義し、詳細な処理をサブクラスで実装するデザインパターン。
1. Template Method パターンの概要
- AbstractClass: アルゴリズムの骨組みを定義し、具体的な処理をサブクラスに委譲する抽象クラス
- このコードでは
Notifier
が該当
- このコードでは
- ConcreteClass:
AbstractClass
を継承し、抽象メソッドを実装して具体的な処理を提供するクラス- このコードでは
EmailNotifier
とSlackNotifier
が該当
- このコードでは
2. 主なクラスとその役割
Notifier
- 抽象クラス(
AbstractClass
) send
メソッドで通知処理の共通フローを定義- ヘッダーを出力
- メッセージをフォーマット
- 宛先を出力
header
,destination
,formatMessage
の抽象メソッドをサブクラスに委譲
- 抽象クラス(
EmailNotifier
Notifier
を継承した具体クラス(ConcreteClass
)- メール通知のヘッダー、宛先、メッセージフォーマットを実装
SlackNotifier
Notifier
を継承した具体クラス(ConcreteClass
)- Slack 通知のヘッダー、宛先、メッセージフォーマットを実装
3. UML クラス図
4. Template Method パターンの利点
- コードの再利用: 共通の処理フローをスーパークラスにまとめることで、コードの重複を削減
- 拡張性: 新しい通知方法を追加する場合も、
Notifier
を継承して抽象メソッドを実装するだけで対応可能 - 一貫性: 共通の処理フローをスーパークラスで定義することで、処理の一貫性を確保
この設計は、共通の処理フローを持つが、一部の処理が異なる場合に非常に有効であり、コードの保守性と拡張性を向上させる。