Commandパターンとは
振る舞いに関するデザインパターンの一つ。リクエストをそれに関する情報をすべて保持する独立したオブジェクトとして保持することにより、リクエストをメソッドの引数にしたり、リクエストの遅延実行、キューイング等を行うことができるようになる。
長所
- 処理を起動するクラスを実際に処理をするクラスから分離可能。(単一責任の原則)
- クライアント側を修正せずに新規コマンドを追加可能。
- 命令の取り消し・再実行や遅延実行の実装が可能。
- 単純にコマンドをまとめて複雑な命令を作成可能。
短所
- コードが複雑化する。
利用場面
- 操作・命令をパラメータとして利用したい場合。
- 操作・命令の再実行・取り消し・遅延実行等を行いたい場合。
クラス図

Command
ConcreteCommandに共通のインターフェースを宣言する。基本的には命令を実行するためのメソッドを一つだけ宣言する。
Concrete Command
Commandインターフェースを実装する。仕事を独立して実行せず、Reciever役にリクエストを渡す。
Receiver
Concrete Commandが命令を実行するとき対象となるクラス。Commandからリクエストを受けとり、実際の作業を実行する。
Invoker
命令の実行を行うクラス。Commandインターフェースで宣言されている、命令実行メソッドを呼び出す。
実装例
Command
package main
type Command interface {
execute()
}
Concrete Command
package main
import (
"fmt"
)
type InputCommand struct {
editor *Editor
text string
}
func NewInputCommand(text string, editor *Editor) *InputCommand {
return &InputCommand{
editor: editor,
text: text,
}
}
func (c *InputCommand) execute() {
fmt.Printf("<< Input command >> (%s)\n", c.text)
c.editor.InputText(c.text)
c.editor.Show()
}
package main
import (
"fmt"
)
type ClearCommand struct {
editor *Editor
}
func NewClearCommand(editor *Editor) *ClearCommand {
return &ClearCommand{editor: editor}
}
func (c *ClearCommand) execute() {
fmt.Println("<< Clear command >>")
c.editor.InputText("")
c.editor.Show()
}
Receiver
package main
import (
"fmt"
)
// Receiver
type Editor struct {
text string
}
func NewEditor() *Editor {
return &Editor{}
}
func (e *Editor) InputText(text string) {
e.text = text
}
func (e *Editor) Show() {
fmt.Printf("Editor's text: %s\n", e.text)
}
Invoker
package main
// Invoker(起動者)
// Commandインタフェースで宣言されたexecuteを呼び出し、命令を実行する
// Invokerは具象Commandには依存しない。
type App struct {
editor *Editor
histroy []Command
}
func NewApp(editor *Editor) *App {
return &App{editor: editor}
}
func (a *App) ExecuteCommand(command Command) {
a.histroy = append(a.histroy, command)
command.execute()
}
func (a *App) Input(text string) {
command := NewInputCommand(text, a.editor)
a.executeCommand(command)
}
func (a *App) Undo() {
if len(a.histroy) > 0 {
command := a.histroy[len(a.histroy) - 1]
command.execute()
a.histroy = a.histroy[:len(a.histroy) - 1]
}
}
func (a *App) Clear() {
command := NewClearCommand(a.editor)
a.executeCommand(command)
}
func (a *App) executeCommand(command Command) {
command.execute()
a.histroy = append(a.histroy, command)
}
動作確認
package main
import "fmt"
func main() {
editor := NewEditor()
app := NewApp(editor)
fmt.Println("=== コマンド実行 ===")
app.Input("Hello World")
fmt.Println()
app.Input("This is Command Pattern")
fmt.Println()
app.Clear()
fmt.Println()
fmt.Println("=== Undo実行 ===")
app.Undo()
fmt.Println()
app.Undo()
fmt.Println()
app.Undo()
fmt.Println()
}
>> go run .
=== コマンド実行 ===
<< Input command >> (Hello World)
Editor's text: Hello World
<< Input command >> (This is Command Pattern)
Editor's text: This is Command Pattern
<< Clear command >>
Editor's text:
=== Undo実行 ===
<< Clear command >>
Editor's text:
<< Input command >> (This is Command Pattern)
Editor's text: This is Command Pattern
<< Input command >> (Hello World)
Editor's text: Hello World
コメント