Command Design Pattern in Go

1. Definition

The Command Design Pattern encapsulates a request as an object, thereby allowing users to parameterize clients with different requests, queue requests, and support undoable operations. It decouples the object that invokes the operation from the one that knows how to execute it.

2. Problem Statement

Imagine you're building an application with various operations. If you hardcode each operation's execution logic within the invoker, it becomes inflexible, leading to a tightly coupled system that's hard to extend, maintain, or scale.

3. Solution

Encapsulate each operation within a command object. This command object has a common interface with a method to execute the operation. The invoker simply triggers this method without knowing the specifics of the operation.

4. Real-World Use Cases

1. Undo/redo functionality in software applications.

2. Task scheduling and management systems.

3. Remote control systems where each button press corresponds to a command.

5. Implementation Steps

1. Define a command interface with an Execute() method.

2. Implement concrete command classes for each specific operation, adhering to the command interface.

3. Use an invoker to call the Execute() method on the command object.

4. Optionally, the command object can store state for undoing the command.

6. Implementation in Go

// Command interface
type Command interface {
	Execute()
}
// LightReceiver - an example receiver
type LightReceiver struct{}
func (l *LightReceiver) TurnOn() {
	fmt.Println("Light is ON")
}
func (l *LightReceiver) TurnOff() {
	fmt.Println("Light is OFF")
}
// Concrete Command
type LightOnCommand struct {
	light *LightReceiver
}
func (c *LightOnCommand) Execute() {
	c.light.TurnOn()
}
type LightOffCommand struct {
	light *LightReceiver
}
func (c *LightOffCommand) Execute() {
	c.light.TurnOff()
}
// Invoker
type RemoteControl struct {
	command Command
}
func (r *RemoteControl) SetCommand(command Command) {
	r.command = command
}
func (r *RemoteControl) PressButton() {
	r.command.Execute()
}
// Client code
func main() {
	light := &LightReceiver{}
	onCommand := &LightOnCommand{light}
	offCommand := &LightOffCommand{light}
	remote := &RemoteControl{}
	remote.SetCommand(onCommand)
	remote.PressButton()
	remote.SetCommand(offCommand)
	remote.PressButton()
}

Output:

Light is ON
Light is OFF

Explanation:

1. The Command interface provides a contract for all concrete command implementations.

2. The LightReceiver is a receiver with methods TurnOn() and TurnOff().

3. LightOnCommand and LightOffCommand are concrete command implementations that encapsulate actions for the LightReceiver.

4. The RemoteControl is an invoker that triggers the command's Execute() method.

5. The client sets up the commands and the invoker, and then triggers the commands through the invoker.

7. When to use?

Use the Command Pattern when:

1. You need to decouple an object that invokes operations from the object that knows how to execute these operations.

2. You want to support undo/redo functionality.

3. Operations need to be executed at different times or in sequences.


Comments