春のセール
Command

Command を Go で

Command 振る舞いに関するデザインパターンの一つで リクエストや簡単な操作をオブジェクトに変換します

変換により コマンドの遅延実行や遠隔実行を可能にしたり コマンドの履歴の保存を可能にしたりできます

概念的な例

Command パターンを テレビを例にとってみてみましょう テレビの電源を入れるには 以下のどちらかを押します

  • リモコンのオンのボタン
  • 実際のテレビのオンのボタン

オンにする コマンド・オブジェクトの実装は テレビを受け手として開始します このコマンドの実行メソッドが呼ばれると それは次に TV.on 関数を呼び出します 次に インボーカーを定義します 実際のところ インボーカーは二つあります リモコンとテレビ自身です 両方とも オンにする コマンド・オブジェクトを埋め込んでいます

同じリクエストを複数のインボーカーでラップしていることに注目してください 他のコマンドでも同様です 別々のコマンド・オブジェクトを作成する利点は UI ロジックをビジネス・ロジックから切り離すことです インボーカーごとに異なるハンドラーを開発する必要はありません コマンド・オブジェクトには 実行に必要なすべての情報が含まれています そのため 遅延実行にも使用できます

button.go: インボーカー

package main

type Button struct {
	command Command
}

func (b *Button) press() {
	b.command.execute()
}

command.go: コマンド・インターフェース

package main

type Command interface {
	execute()
}

onCommand.go: 具象コマンド

package main

type OnCommand struct {
	device Device
}

func (c *OnCommand) execute() {
	c.device.on()
}

offCommand.go: 具象コマンド

package main

type OffCommand struct {
	device Device
}

func (c *OffCommand) execute() {
	c.device.off()
}

device.go: 受け手インターフェース

package main

type Device interface {
	on()
	off()
}

tv.go: 具象受け手

package main

import "fmt"

type Tv struct {
	isRunning bool
}

func (t *Tv) on() {
	t.isRunning = true
	fmt.Println("Turning tv on")
}

func (t *Tv) off() {
	t.isRunning = false
	fmt.Println("Turning tv off")
}

main.go: クライアント・コード

package main

func main() {
	tv := &Tv{}

	onCommand := &OnCommand{
		device: tv,
	}

	offCommand := &OffCommand{
		device: tv,
	}

	onButton := &Button{
		command: onCommand,
	}
	onButton.press()

	offButton := &Button{
		command: offCommand,
	}
	offButton.press()
}

output.txt: 実行結果

Turning tv on
Turning tv off

他言語での Command

Command を C# で Command を C++ で Command を Java で Command を PHP で Command を Python で Command を Ruby で Command を Rust で Command を Swift で Command を TypeScript で