ឥរិយាបថ កម្រិតស្មុគស្មាញ: មធ្យម

លំនាំ Command ក្នុង Go

ខ្ចប់ operations សម្រាប់ queuing, audit history និង undo/redo ខណៈដែលរក្សា Go error handling ឱ្យច្បាស់លាស់។

The Problem

Operations such as placing an order, cancelling it, and issuing a refund often need the same extra capabilities: audit history, delayed execution, undo/redo, and a clean separation between the code that requests an action and the code that performs it. If those concerns are embedded directly in handlers, the workflow becomes tightly coupled and hard to extend.

The Solution

The Command pattern wraps each operation in a value that satisfies a small interface. An invoker executes commands, stores history, and coordinates undo/redo. In Go, the pattern works well when you combine interfaces, explicit result values, and ordinary synchronization primitives.

Structure

  • Command interface: Declares Execute, Undo, and Name.
  • Concrete commands: Order placement, cancellation, and refund operations.
  • Invoker: Stores execution history and provides undo/redo.
  • Client: Application code that creates commands and submits them.

Implementation

package main

import "time"

// CommandResult represents the result of executing a command
type CommandResult struct {
	Success bool        `json:"success"`
	Message string      `json:"message"`
	Data    interface{} `json:"data,omitempty"`
}

// OrderData represents order information
type OrderData struct {
	OrderID   string    `json:"orderId"`
	Amount    float64   `json:"amount,omitempty"`
	Status    string    `json:"status"`
	Timestamp time.Time `json:"timestamp"`
}

// Command defines the interface for all commands
type Command interface {
	Execute() CommandResult
	Undo() CommandResult
	Name() string
}

Best Practices

  • Keep the command interface small so new commands are cheap to add.
  • Model failure explicitly. Go code should return results and errors rather than relying on hidden state.
  • Protect shared history with a mutex if multiple goroutines can execute commands concurrently.
  • Use commands when you need history, queuing, or undo. For one-off service calls, a plain method call is usually enough.
  • Avoid coupling commands to transport or framework details. They should represent business operations, not HTTP handlers.

When to Use

  • You need operation history, undo/redo, queuing, or delayed execution.
  • The caller should not know how the work is performed internally.
  • You want to treat operations as values that can be stored, retried, or scheduled.

When NOT to Use

  • The operation is a simple method call with no history or coordination concerns.
  • Wrapping every function call in a command would add ceremony without value.
  • The extra allocation and bookkeeping would hurt a hot path without providing useful decoupling.