Go中可通过接口、channel和goroutine实现“命令+观察者”组合模式:命令封装操作与元信息,观察者监听事件,执行器异步执行并广播生命周期事件,实现解耦。

在 Go 中实现“命令 + 观察者”组合模式来支持异步请求执行与事件通知,核心是解耦请求发起者(Invoker)、具体操作(Command)、执行器(Executor)和监听响应的观察者(Observer)。Go 本身没有类继承和接口强制实现,但可通过接口、channel 和 goroutine 自然达成这一设计目标。
定义命令接口与具体命令
命令封装请求参数、执行逻辑和可选的上下文。所有命令需实现统一接口,便于调度器统一处理:
type Command interface {
Execute() error
ID() string
// 可选:支持取消、超时、重试等元信息
Timeout() time.Duration
}例如一个发送邮件的命令:
type SendEmailCommand struct {
To string
Subject string
Body string
cmdID string
}
func (c SendEmailCommand) ID() string { return c.cmdID }
func (c SendEmailCommand) Timeout() time.Duration { return 5 * time.Second }
func (c SendEmailCommand) Execute() error {
// 模拟异步发送(实际中可调用 SMTP 客户端)
time.Sleep(2 time.Second)
fmt.Printf("Email sent to %s\n", c.To)
return nil
}
构建观察者接口与事件总线
观察者监听命令生命周期事件(如开始、成功、失败、超时)。使用 channel 实现松耦合通知:
立即学习“go语言免费学习笔记(深入)”;
type Event struct {
CommandID string
Type string // "started", "completed", "failed", "timeout"
Err error
Data map[string]interface{}
}
type Observer interface {
OnEvent(event Event)
}
// 全局事件总线(简单版,生产可用需加锁或用 sync.Map)
var observers = make([]Observer, 0)
func RegisterObserver(obs Observer) {
observers = append(observers, obs)
}
func Notify(event Event) {
for _, o := range observers {
go o.OnEvent(event) // 异步通知,避免阻塞主流程
}
}
异步命令执行器(带生命周期通知)
执行器接收命令,启动 goroutine 执行,并主动推送事件。它不依赖外部调度器,自身完成“发令-执行-广播”闭环:
func ExecuteAsync(cmd Command) {
cmdID := cmd.ID()
// 1. 发送 started 事件
Notify(Event{
CommandID: cmdID,
Type: "started",
Data: map[string]interface{}{"command": fmt.Sprintf("%T", cmd)},
})
// 2. 启动带超时控制的异步执行
done := make(chan error, 1)
go func() {
done <- cmd.Execute()
}()
select {
case err := <-done:
if err != nil {
Notify(Event{
CommandID: cmdID,
Type: "failed",
Err: err,
})
} else {
Notify(Event{
CommandID: cmdID,
Type: "completed",
})
}
case <-time.After(cmd.Timeout()):
Notify(Event{
CommandID: cmdID,
Type: "timeout",
})
}}
实现具体观察者并集成使用
观察者可记录日志、触发回调、更新状态或转发消息。例如一个日志观察者和一个 Webhook 观察者:
type LogObserver struct{}
func (l LogObserver) OnEvent(e Event) {
switch e.Type {
case "started":
log.Printf("[CMD] %s started", e.CommandID)
case "completed":
log.Printf("[CMD] %s completed", e.CommandID)
case "failed":
log.Printf("[CMD] %s failed: %v", e.CommandID, e.Err)
case "timeout":
log.Printf("[CMD] %s timed out", e.CommandID)
}
}
type WebhookObserver struct {
URL string
}
func (w WebhookObserver) OnEvent(e Event) {
payload, _ := json.Marshal(e)
http.Post(w.URL, "application/json", bytes.NewBuffer(payload))
}
// 使用示例
func main() {
RegisterObserver(LogObserver{})
RegisterObserver(WebhookObserver{URL: "https://www.php.cn/link/92fb24d9addf85cd522569d24d24b160"})
cmd := &SendEmailCommand{
To: "user@example.com",
Subject: "Welcome",
Body: "Hello from Go!",
cmdID: "cmd-123",
}
ExecuteAsync(cmd)
time.Sleep(6 * time.Second) // 等待异步完成(实际项目中用 sync.WaitGroup 或 context 控制)}
该实现不依赖第三方框架,仅用标准库即可支撑高内聚、低耦合的异步命令流。关键点在于:命令只关心“做什么”,观察者只关心“发生了什么”,执行器负责“何时做+怎么通知”。扩展时可增加命令队列、优先级、重试策略或与 context 集成以支持取消。










