命令模式属于行为型设计模式,核心思想是将请求封装成独立的对象,让请求的调用者和接收者之间不再直接耦合,同时可以支持命令的排队、记录、撤销等操作。在Golang中实现命令模式,需要结合接口和结构体来定义命令的规范,再通过具体的结构体实现不同的命令逻辑。

命令模式的核心角色
命令模式通常包含以下几个核心角色:
- 命令接口:定义所有命令需要实现的执行方法,是命令的统一规范
- 具体命令:实现命令接口,绑定对应的接收者,调用接收者的具体方法完成操作
- 接收者:真正执行命令逻辑的对象,包含具体的业务方法
- 调用者:持有命令对象,触发命令的执行,不需要知道命令的具体实现细节
- 客户端:创建具体的命令对象,设置对应的接收者,将命令交给调用者执行
Golang实现命令模式的基本步骤
1. 定义命令接口
首先定义命令的通用接口,所有具体命令都需要实现该接口的Execute方法,部分场景还可以增加Undo方法支持撤销操作。
// Command 命令接口,定义命令的执行和撤销方法
type Command interface {
Execute() // 执行命令
Undo() // 撤销命令
}
2. 定义接收者
接收者是实际执行业务逻辑的对象,这里以一个简单的灯控设备为例,接收者包含开灯和关灯的方法。
// Light 接收者,代表灯设备
type Light struct {
isOn bool // 记录灯的状态
}
// On 开灯方法
func (l *Light) On() {
l.isOn = true
fmt.Println("灯已打开")
}
// Off 关灯方法
func (l *Light) Off() {
l.isOn = false
fmt.Println("灯已关闭")
}
3. 实现具体命令
具体命令需要绑定对应的接收者,实现命令接口的方法,调用接收者的业务方法完成操作。
// LightOnCommand 开灯命令,实现Command接口
type LightOnCommand struct {
light *Light // 绑定的接收者
}
// NewLightOnCommand 创建开灯命令的构造函数
func NewLightOnCommand(light *Light) *LightOnCommand {
return &LightOnCommand{
light: light,
}
}
// Execute 执行开灯命令
func (c *LightOnCommand) Execute() {
c.light.On()
}
// Undo 撤销开灯命令,即执行关灯
func (c *LightOnCommand) Undo() {
c.light.Off()
}
// LightOffCommand 关灯命令,实现Command接口
type LightOffCommand struct {
light *Light // 绑定的接收者
}
// NewLightOffCommand 创建关灯命令的构造函数
func NewLightOffCommand(light *Light) *LightOffCommand {
return &LightOffCommand{
light: light,
}
}
// Execute 执行关灯命令
func (c *LightOffCommand) Execute() {
c.light.Off()
}
// Undo 撤销关灯命令,即执行开灯
func (c *LightOffCommand) Undo() {
c.light.On()
}
4. 定义调用者
调用者持有命令对象,负责触发命令的执行,不需要关心命令的具体实现,只需要调用命令的Execute方法即可。
// RemoteControl 调用者,代表遥控器
type RemoteControl struct {
command Command // 当前持有的命令
}
// SetCommand 设置要执行的命令
func (r *RemoteControl) SetCommand(command Command) {
r.command = command
}
// PressButton 按下按钮,执行命令
func (r *RemoteControl) PressButton() {
if r.command != nil {
r.command.Execute()
}
}
// PressUndoButton 按下撤销按钮,撤销命令
func (r *RemoteControl) PressUndoButton() {
if r.command != nil {
r.command.Undo()
}
}
5. 客户端调用示例
客户端负责创建接收者、具体命令,将命令设置给调用者,触发命令执行。
package main
import "fmt"
func main() {
// 创建接收者
light := &Light{}
// 创建具体命令
lightOnCmd := NewLightOnCommand(light)
lightOffCmd := NewLightOffCommand(light)
// 创建调用者
remote := &RemoteControl{}
// 执行开灯命令
remote.SetCommand(lightOnCmd)
remote.PressButton()
// 执行关灯命令
remote.SetCommand(lightOffCmd)
remote.PressButton()
// 撤销上一次的关灯命令
remote.PressUndoButton()
}
命令模式的优势与适用场景
使用命令模式封装功能后,调用者和接收者完全解耦,后续新增命令只需要新增实现命令接口的结构体即可,不需要修改调用者的代码,符合开闭原则。该模式适合以下场景:
- 需要将请求调用者和请求接收者解耦的场景
- 需要支持命令排队、记录、撤销、重做等功能的场景
- 需要将一组操作组合成宏命令的场景
在Golang中利用接口和结构体实现命令模式,代码结构清晰,扩展性强,能够很好地应对业务功能的变化需求。