🧩 Command パターン
✅ 設計意図
- 実行内容を「命令」としてオブジェクト化する
- 状態ごとの処理を実行タイミングに応じて呼び出す
✅ 適用理由
- 状態というよりは、「実行する内容をあとから差し替える」文脈で使える
- 操作履歴や Undo/Redo が関係する場合に有効
✅ コード例
- TypeScript
- PHP
- Python
// コマンドインターフェース
interface PublishCommand {
execute(): void;
}
// 各状態の処理をコマンド化
class DraftPublishCommand implements PublishCommand {
execute(): void {
console.log("レビュー依頼を送信");
}
}
class ReviewPublishCommand implements PublishCommand {
execute(): void {
console.log("公開しました");
}
}
class PublishedPublishCommand implements PublishCommand {
execute(): void {
console.log("すでに公開済みです");
}
}
// Invoker(呼び出し役)
class Document {
private command: PublishCommand;
constructor(command: PublishCommand) {
this.command = command;
}
setCommand(command: PublishCommand): void {
this.command = command;
}
publish(): void {
this.command.execute();
}
}
// 利用例
const doc = new Document(new DraftPublishCommand());
doc.publish(); // → レビュー依頼
doc.setCommand(new ReviewPublishCommand());
doc.publish(); // → 公開
doc.setCommand(new PublishedPublishCommand());
doc.publish(); // → すでに公開済み
<?php
interface PublishCommand {
public function execute(): void;
}
class DraftPublishCommand implements PublishCommand {
public function execute(): void {
echo "レビュー依頼を送信\n";
}
}
class ReviewPublishCommand implements PublishCommand {
public function execute(): void {
echo "公開しました\n";
}
}
class PublishedPublishCommand implements PublishCommand {
public function execute(): void {
echo "すでに公開済みです\n";
}
}
class Document {
private PublishCommand $command;
public function __construct(PublishCommand $command) {
$this->command = $command;
}
public function setCommand(PublishCommand $command): void {
$this->command = $command;
}
public function publish(): void {
$this->command->execute();
}
}
// 利用例
$doc = new Document(new DraftPublishCommand());
$doc->publish();
$doc->setCommand(new ReviewPublishCommand());
$doc->publish();
$doc->setCommand(new PublishedPublishCommand());
$doc->publish();
from abc import ABC, abstractmethod
class PublishCommand(ABC):
@abstractmethod
def execute(self):
pass
class DraftPublishCommand(PublishCommand):
def execute(self):
print("レビュー依頼を送信")
class ReviewPublishCommand(PublishCommand):
def execute(self):
print("公開しました")
class PublishedPublishCommand(PublishCommand):
def execute(self):
print("すでに公開済みです")
class Document:
def __init__(self, command: PublishCommand):
self._command = command
def set_command(self, command: PublishCommand):
self._command = command
def publish(self):
self._command.execute()
# 利用例
doc = Document(DraftPublishCommand())
doc.publish()
doc.set_command(ReviewPublishCommand())
doc.publish()
doc.set_command(PublishedPublishCommand())
doc.publish()
✅ 解説
このコードは Command
パターン を使用して、ドキュメントの公開処理をコマンドとしてカプセル化し、動的に切り替えられる設計を実現している。
Command
パターンは、操作をオブジェクトとして表現し、操作の実行を遅延させたり、動的に切り替えたりするデザインパターン。
1. Command パターンの概要
- Command: 操作を表現するインターフェース
- このコードでは
PublishCommand
が該当
- このコードでは
- ConcreteCommand:
Command
を実装し、具体的な操作を定義するクラス- このコードでは
DraftPublishCommand
,ReviewPublishCommand
,PublishedPublishCommand
が該当
- このコードでは
- Invoker:
Command
を実行する役割を持つクラス- このコードでは
Document
が該当
- このコードでは
- Client:
Command
を生成し、Invoker
に渡す役割を持つ- このコードでは
new Document(new DraftPublishCommand())
の部分が該当
- このコードでは
2. 主なクラスとその役割
PublishCommand
- コマンドの共通インターフェース
execute(): void
メソッドを定義
DraftPublishCommand
,ReviewPublishCommand
,PublishedPublishCommand
PublishCommand
を実装した具体的なコマンドクラス- 各クラスで異なる公開処理を提供
DraftPublishCommand
: 「レビュー依頼を送信」ReviewPublishCommand
: 「公開しました」PublishedPublishCommand
: 「すでに公開済みです」
Document
- Invoker クラス
- コンストラクタで
PublishCommand
を受け取り、publish
メソッドでコマンドを実行 setCommand
メソッドでコマンドを動的に切り替え可能
3. UML クラス図
4. Command パターンの利点
- 操作のカプセル化: 操作をオブジェクトとして表現することで、操作の実行を遅延させたり、動的に切り替えたりできる
- 柔軟性: 新しい操作を追加する場合も、
PublishCommand
を実装するだけで対応可能 - Invoker の汎用性:
Document
はどのコマンドでも実行可能で、汎用性が高い
この設計は、操作をオブジェクトとして扱うことで、柔軟性と拡張性を向上させる。特に、操作の切り替えや履歴管理が必要な場面で有効に機能する。