コマンドパターン
コマンドパターン(Command Pattern) は、操作をオブジェクトとしてカプセル化し、それを呼び出し元から分離することで、操作の呼び出し、取り消し、キューイングを柔軟に管理できるようにするデザインパターンです。このパターンでは、リクエストをオブジェクトとして表現し、操作を実行するオブジェクト(コマンド)と操作の受け手(レシーバー)を疎結合に保ちます。
コマンドパターンは、メニューの操作を抽象化したい場合や複数の操作をまとめて管理する必要がある場合に役立ちます。たとえば、アンドゥ/リドゥの操作や、複数の操作をバッチで処理する場合に使用されます。
TypeScriptでのコマンドパターンの実装
以下に、TypeScriptでコマンドパターンを実装する例を紹介します。この例では、リモコンを使ってライトを操作するシンプルなシナリオを取り上げます。
ライトの操作の例
typescript
// コマンドインターフェース
interface Command {
execute(): void;
undo(): void;
}
// レシーバークラス(実際に操作を実行する)
class Light {
turnOn(): void {
console.log('The light is ON');
}
turnOff(): void {
console.log('The light is OFF');
}
}
// ライトを点けるコマンド
class LightOnCommand implements Command {
private light: Light;
constructor(light: Light) {
this.light = light;
}
execute(): void {
this.light.turnOn();
}
undo(): void {
this.light.turnOff();
}
}
// ライトを消すコマンド
class LightOffCommand implements Command {
private light: Light;
constructor(light: Light) {
this.light = light;
}
execute(): void {
this.light.turnOff();
}
undo(): void {
this.light.turnOn();
}
}
// インボーカークラス(コマンドを呼び出す)
class RemoteControl {
private command: Command | null = null;
setCommand(command: Command): void {
this.command = command;
}
pressButton(): void {
if (this.command) {
this.command.execute();
}
}
pressUndo(): void {
if (this.command) {
this.command.undo();
}
}
}
// 実際の使用例
const light = new Light();
const lightOnCommand = new LightOnCommand(light);
const lightOffCommand = new LightOffCommand(light);
const remote = new RemoteControl();
// ライトを点ける
remote.setCommand(lightOnCommand);
remote.pressButton(); // "The light is ON"
remote.pressUndo(); // "The light is OFF"
// ライトを消す
remote.setCommand(lightOffCommand);
remote.pressButton(); // "The light is OFF"
remote.pressUndo(); // "The light is ON"
解説
Commandインターフェース
Command
インターフェースは、execute
メソッドとundo
メソッドを定義しています。これにより、各コマンドが実行と取り消しの操作を持つことが保証されます。
Lightクラス(レシーバー)
Light
クラスは、実際の操作を実行する役割を持つレシーバーです。このクラスには、ライトを点けたり消したりするためのメソッドがあります。
LightOnCommandとLightOffCommandクラス(具体的なコマンド)
LightOnCommand
とLightOffCommand
は、Command
インターフェースを実装した具体的なコマンドクラスです。それぞれ、ライトを点ける操作と消す操作を実行します。また、undo
メソッドを使って操作の取り消しを行います。
RemoteControlクラス(インボーカー)
RemoteControl
クラスは、コマンドを呼び出す役割を持つインボーカークラスです。このクラスは、setCommand
メソッドでコマンドをセットし、pressButton
メソッドでコマンドを実行し、pressUndo
メソッドで操作を取り消します。
実際の使用例
RemoteControl
を使って、ライトを点けたり消したりする操作を行います。pressButton
でコマンドを実行し、pressUndo
で操作を取り消すことができます。
利点
- 疎結合の実現: コマンドの実行を、リクエストを出す側(インボーカー)と実際に実行する側(レシーバー)から分離することで、疎結合を実現します。
- 操作の履歴管理: コマンドをオブジェクトとして扱うことで、操作の履歴を管理したり、取り消し(アンドゥ)を実装するのが容易になります。
- 柔軟な拡張性: 新しい操作を追加する際に、既存のコードに大きな変更を加えることなく新しいコマンドを追加できます。
使用例
- GUI操作の抽象化: GUIのボタン操作やメニューアイテムの選択をコマンドとして扱うことで、動作を抽象化しやすくします。
- アンドゥ/リドゥの実装: アンドゥやリドゥ機能を実装する際に、コマンドの履歴を管理することで、操作の取り消しや再実行を簡単に行うことができます。
- タスクのキューイング: コマンドをキューに入れて順次実行することで、複数のタスクを柔軟に管理できます。
まとめ
コマンドパターンは、操作をオブジェクトとしてカプセル化し、呼び出し元から分離することで、柔軟に操作を管理するための強力なパターンです。TypeScriptでの実装を通じて、操作の実行、取り消し、呼び出しの抽象化の仕組みを理解できました。
このパターンを活用することで、特にユーザーインターフェース操作の抽象化や操作の履歴管理が求められるシステムにおいて、保守性と拡張性を高めることができます。