コマンドパターン
定義
操作(コマンド)をオブジェクトとしてカプセル化し、操作の実行と操作の内容を分離することを目的としています。
これにより、操作の履歴を保持したり、操作を取り消したり、再実行したりすることが容易になります。
コマンドパターンの構成要素
-
コマンドインターフェース(ICommand):
コマンドオブジェクトが実装すべきインターフェースを定義します。一般的には、Executeメソッドを持ちます。 -
具体的なコマンドクラス(ConcreteCommand):
コマンドインターフェースを実装し、特定のアクションを実行します。 -
レシーバー(Receiver):
コマンドが実行される対象オブジェクトです。 -
インボーカー(Invoker):
コマンドを呼び出す役割を持ちます。コマンドオブジェクトを保持し、適切なタイミングでExecuteメソッドを呼び出します。 -
クライアント(Client):
コマンド、レシーバー、インボーカーを構成して操作を実行するクラスです。
使用例
- プレイヤーアクション: プレイヤーの操作をコマンドとしてカプセル化し、操作履歴の管理や操作の取り消しを可能にする。
- メニューシステム: メニュー項目の選択やアクションをコマンドとしてカプセル化し、メニューの動的な変更を容易にする。
- AI行動: AIの行動をコマンドとしてカプセル化し、行動の切り替えやシーケンスを管理する。
利点
- 拡張性: 新しいコマンドを追加する際に、既存のコードを変更する必要がない。
- 取り消し/やり直し: コマンドの履歴を保持することで、取り消しややり直しが可能。
- 柔軟性: 同じインターフェースを持つ異なるコマンドを簡単に切り替えることができる。
欠点
- 複雑性の増加: コマンドクラスやインボーカークラスの数が増えるため、設計が複雑になる場合がある。
- リソース消費: コマンドの履歴を保持するため、メモリを多く消費する可能性がある。
コマンドパターンの実装例
コマンドインターフェース
public interface ICommand {
void Execute();
void Undo();
}
具体的なコマンドクラス
using UnityEngine;
public class MoveUpCommand : ICommand {
private Transform player;
private Vector3 previousPosition;
public MoveUpCommand(Transform player) {
this.player = player;
}
public void Execute() {
previousPosition = player.position;
player.position += Vector3.up;
}
public void Undo() {
player.position = previousPosition;
}
}
public class MoveDownCommand : ICommand {
private Transform player;
private Vector3 previousPosition;
public MoveDownCommand(Transform player) {
this.player = player;
}
public void Execute() {
previousPosition = player.position;
player.position += Vector3.down;
}
public void Undo() {
player.position = previousPosition;
}
}
コマンドの使用例
using UnityEngine;
using System.Collections.Generic;
public class GameManager : MonoBehaviour {
private Stack<ICommand> commandHistory = new Stack<ICommand>();
public Transform player;
void Update() {
if (Input.GetKeyDown(KeyCode.W)) {
ICommand moveUp = new MoveUpCommand(player);
moveUp.Execute();
commandHistory.Push(moveUp);
}
if (Input.GetKeyDown(KeyCode.S)) {
ICommand moveDown = new MoveDownCommand(player);
moveDown.Execute();
commandHistory.Push(moveDown);
}
if (Input.GetKeyDown(KeyCode.Z) && commandHistory.Count > 0) {
ICommand lastCommand = commandHistory.Pop();
lastCommand.Undo();
}
}
}
ちょっとだけ変えたプログラム1
MoveUpCommand と MoveDownCommand の内容が重複してるので1つにまとめてみた
public interface ICommand {
void Execute();
void Undo();
}
using UnityEngine;
public class MoveCommand : ICommand {
private Transform player;
private Vector3 direction;
private Vector3 previousPosition;
public MoveCommand(Transform player, Vector3 direction) {
this.player = player;
this.direction = direction;
}
public void Execute() {
previousPosition = player.position;
player.position += direction;
}
public void Undo() {
player.position = previousPosition;
}
}