元素码农
基础
UML建模
数据结构
算法
设计模式
网络
TCP/IP协议
HTTPS安全机制
WebSocket实时通信
数据库
sqlite
postgresql
clickhouse
后端
rust
go
java
php
mysql
redis
mongodb
etcd
nats
zincsearch
前端
浏览器
javascript
typescript
vue3
react
游戏
unity
unreal
C++
C#
Lua
App
android
ios
flutter
react-native
安全
Web安全
测试
软件测试
自动化测试 - Playwright
人工智能
Python
langChain
langGraph
运维
linux
docker
工具
git
svn
🌞
🌙
目录
▶
设计原则
单一职责原则
开闭原则
里氏替换原则
依赖倒置原则
接口隔离原则
迪米特法则
▶
创建型模式
工厂方法模式
抽象工厂
单例模式
建造者模式
原型模式
▶
结构型模式
适配器模式
装饰器模式
代理模式
外观模式
组合模式
桥接模式
享元模式
▶
行为型模式
策略模式
观察者模式
命令模式
模板方法模式
状态模式
责任链模式
迭代器模式
中介者模式
访问者模式
备忘录模式
解释器模式
发布时间:
2025-03-21 15:22
↑
☰
# 命令模式 ## 概述 命令模式(Command Pattern)是一种行为型设计模式,它将一个请求封装成一个对象,从而使你可以用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。 ## 问题场景 在软件开发中,我们经常会遇到以下场景: 1. 需要将请求发送者和接收者解耦 2. 需要将请求参数化 3. 需要支持撤销/重做操作 4. 需要将一组操作组合在一起 ## 解决方案 命令模式通过以下方式解决这些问题: ```mermaid classDiagram class Command { <<interface>> +execute() +undo() } class ConcreteCommand { -receiver: Receiver +execute() +undo() } class Invoker { -command: Command +setCommand(Command) +executeCommand() +undoCommand() } class Receiver { +action() } class Client Command <|.. ConcreteCommand Invoker o-- Command ConcreteCommand --> Receiver Client --> Invoker Client --> ConcreteCommand ``` 主要角色: 1. 命令(Command): 声明执行操作的接口 2. 具体命令(ConcreteCommand): 将一个接收者对象绑定于一个动作 3. 调用者(Invoker): 要求该命令执行这个请求 4. 接收者(Receiver): 知道如何实施与执行一个请求相关的操作 ## 代码示例 ### 1. 基本实现 ```go // Command 命令接口 type Command interface { Execute() string Undo() string } // Receiver 接收者 type Receiver struct { name string } func NewReceiver(name string) *Receiver { return &Receiver{name: name} } func (r *Receiver) Action() string { return fmt.Sprintf("Receiver %s is handling the request", r.name) } func (r *Receiver) UndoAction() string { return fmt.Sprintf("Receiver %s is undoing the request", r.name) } // ConcreteCommand 具体命令 type ConcreteCommand struct { receiver *Receiver } func NewConcreteCommand(receiver *Receiver) Command { return &ConcreteCommand{receiver: receiver} } func (c *ConcreteCommand) Execute() string { return c.receiver.Action() } func (c *ConcreteCommand) Undo() string { return c.receiver.UndoAction() } // Invoker 调用者 type Invoker struct { command Command } func NewInvoker() *Invoker { return &Invoker{} } func (i *Invoker) SetCommand(command Command) { i.command = command } func (i *Invoker) ExecuteCommand() string { return i.command.Execute() } func (i *Invoker) UndoCommand() string { return i.command.Undo() } ``` ### 2. 实际应用示例 ```go // 以文本编辑器为例 // TextFileOperator 文本操作接口 type TextFileOperator interface { Execute() string Undo() string } // TextFile 文本文件 type TextFile struct { name string content string } func NewTextFile(name string) *TextFile { return &TextFile{name: name} } func (t *TextFile) Write(text string) string { t.content += text return fmt.Sprintf("Writing text to %s", t.name) } func (t *TextFile) Erase() string { if len(t.content) > 0 { t.content = t.content[:len(t.content)-1] } return fmt.Sprintf("Erasing text from %s", t.name) } // WriteCommand 写入命令 type WriteCommand struct { textFile *TextFile text string } func NewWriteCommand(textFile *TextFile, text string) TextFileOperator { return &WriteCommand{ textFile: textFile, text: text, } } func (w *WriteCommand) Execute() string { return w.textFile.Write(w.text) } func (w *WriteCommand) Undo() string { return w.textFile.Erase() } // TextEditor 文本编辑器 type TextEditor struct { history []TextFileOperator } func NewTextEditor() *TextEditor { return &TextEditor{ history: make([]TextFileOperator, 0), } } func (e *TextEditor) ExecuteCommand(command TextFileOperator) string { result := command.Execute() e.history = append(e.history, command) return result } func (e *TextEditor) Undo() string { if len(e.history) > 0 { command := e.history[len(e.history)-1] e.history = e.history[:len(e.history)-1] return command.Undo() } return "Nothing to undo" } // 使用示例 func main() { // 创建文本文件 file := NewTextFile("example.txt") // 创建编辑器 editor := NewTextEditor() // 执行写入命令 writeCmd1 := NewWriteCommand(file, "Hello") fmt.Println(editor.ExecuteCommand(writeCmd1)) writeCmd2 := NewWriteCommand(file, " World") fmt.Println(editor.ExecuteCommand(writeCmd2)) // 撤销最后一次写入 fmt.Println(editor.Undo()) // 撤销第一次写入 fmt.Println(editor.Undo()) } ``` ## 适用场景 1. 参数化对象 - 需要将请求参数化 - 需要在不同时刻指定请求 2. 队列请求 - 需要将请求排队 - 需要在不同时刻执行请求 3. 支持撤销 - 需要支持撤销操作 - 需要维护操作历史 ## 优缺点 ### 优点 1. 解耦请求者和接收者 - 发送者和接收者之间没有直接引用 - 降低系统的耦合度 2. 容易扩展新命令 - 符合开闭原则 - 方便添加新的命令 3. 支持撤销和重做 - 可以实现撤销操作 - 可以保存命令历史 ### 缺点 1. 可能产生大量命令类 - 每个具体命令都需要一个类 - 增加系统的复杂度 2. 命令的状态保存 - 需要考虑命令的状态保存 - 可能占用较多内存 ## 实现要点 1. 命令接口设计 - 定义统一的命令接口 - 考虑是否需要撤销操作 2. 命令对象封装 - 封装请求相关信息 - 保持命令的独立性 3. 命令历史管理 - 维护命令的执行历史 - 实现撤销和重做功能 ## 相关模式 1. 组合模式 - 可以组合多个命令 - 创建宏命令 2. 备忘录模式 - 可以保存命令的状态 - 支持撤销操作 3. 原型模式 - 可以复制命令对象 - 创建相似的命令 ## 总结 命令模式是一种将请求封装成对象的行为型设计模式,它的核心价值在于: 1. 解耦 - 将请求发送者和接收者解耦 - 提高系统的灵活性 2. 可扩展性 - 易于添加新的命令 - 不影响现有代码 3. 可维护性 - 命令的封装和管理 - 支持撤销和重做 在实际开发中,命令模式常用于需要将请求参数化、支持撤销操作或需要将请求排队的场景。通过命令模式,我们可以更好地管理和维护这些操作,使系统更加灵活和可扩展。