実現したい機能・実装要件
-
動作を分離・抽象化したい
- 機能内のある動作について、今後、追加・拡張・改修が予想され、疎結合にすることで、柔軟に対応したい
- 単一責任の原則(SRP)を守り、処理の呼び出しと実装を独立させたい
-
取り消し・再実行をしたい
- 実行に対するリバート処理(undo)や再実行(redo)機能を実装したい
- 実行履歴を保持し、過去の状態にしたい
-
処理の実行順を柔軟に制御したい
- 処理をキューイングしたり、スケジューリングで順序を制御したい
- バッチ実行や非同期処理など、柔軟な実行モデルに対応したい
Commandパターン
- Client
- 全体の制御処理を担う
- Invokerに、ConcreateCommandを依存性注入で渡すことで、Invokerから任意のコマンド処理を実行することが可能
- Invoker
- Commandの呼び出し役
- Command
- コマンド処理を抽象化するインターフェイス
- Invokerと、ConcreateCommandを疎結合にしている
- ConcreateCommand
- コマンド処理の本体
- Receiver
- コマンド処理の事後処理や、処理結果をClientに渡す役割を担う
- クリーンアーキテクチャのPresenter的な立ち位置
サンプル
undo_redo
- socket通信で受け取ったメッセージに対応したCommandクラスを実行する
動作の分離
-
i_commandインターフェイスを、継承することで、4種類のCommandクラスを作成
- Up
- Down
- Undo
- Redo
- 依存関係の末端であるCommandクラス郡は、柔軟にCommandの追加・拡張・修正ができるようになった
取り消し・再実行
- Commandクラスを使った取り消し・再実行は、下記により実現させる
- 直前の実行の打ち消し
- 直前処理を確認し同じものを実行する
- Historyクラスに履歴を持たせることで、undo・redoのイベントをトリガーした際に、対応したCommandクラスを特定できる
処理の実行順を制御する
-
Clientクラスがこの役割を担う
- 新たな動作が追加された場合も、invoke_command()の処理を追加するだけで対応できる