Patterns: behavior · 3 MIN READ

Command: represent an action as a value

Make actions queueable or reversible without claiming every effect can be undone.

Make actions queueable or reversible without claiming every effect can be undone. Command packages an operation and its receiver into a value that can be executed later. Trace the worked Go example, then compare the benefit with the cost before applying this design to your own project.

Behavioral pattern · A MAP OF THE IDEA

  1. Create action with receiver and arguments
  2. Execute through a command value
  3. Restore prior state only where valid

Useful when

  • Actions need queuing, history or local undo
  • The invoker should not know receiver details

Watch out

  • Undo assumes a defined state history
  • Durable commands need explicit schemas

Implementation & operation cost: Medium

Fit depends on the task

Small tool or CLI4/5
Domain-rich application4/5
Independent distributed services4/5

Editorial suitability, not benchmarks or a universal ranking. Styles describe different axes and can be combined.

01

The design decision

Command packages an operation and its receiver into a value that can be executed later. It can support local undo when enough previous state is retained. Sending an email or charging a remote payment is not reversed by merely invoking a method named Undo.

02

A complete Go example

Read this program from the entry point and follow the calls shown in the diagram. The output is included at the end so you can check the behavior without a compiler.

go
package main

import (
	"fmt"
)

type Rename struct {
	target         *string
	next, previous string
	done           bool
}

func (c *Rename) Do() {
	if c.done {
		return
	}
	c.previous = *c.target
	*c.target = c.next
	c.done = true
}
func (c *Rename) Undo() {
	if !c.done {
		return
	}
	*c.target = c.previous
	c.done = false
}

func main() {
	name := "draft"
	c := &Rename{target: &name, next: "report"}
	c.Do()
	fmt.Println(name)
	c.Undo()
	fmt.Println(name)
}

// Output:
// report
// draft
Read the code

Rename captures the receiver, requested name and old name. Do is guarded against repetition; Undo restores the prior value. This assumes no independent mutation between execution and undo and one owner of the receiver.

03

Tradeoffs and the simpler alternative

For durable queues, serialize a command schema and validate it on receipt; a closure cannot survive process exit. Undo of external work often needs a compensating business action with its own possible failures. Use a direct function for one immediate action.

TAKE THIS WITH YOU

Captures an action and the data needed to execute it. For durable queues, serialize a command schema and validate it on receipt; a closure cannot survive process exit. Undo of external work often needs a compensating business action with its own possible failures. Use a direct function for one immediate action.

Check your understanding

Which statement best describes Command: represent an action as a value?

Go to the source

Progress stays in this browser. No account needed.