Golang学习笔记_41——观察者模式
Golang学习笔记_38——享元模式
Golang学习笔记_39——策略模式
Golang学习笔记_40——模版方法模式
文章目录
- 一、核心概念
- 1. 定义
- 2. 解决的问题
- 3. 核心角色
- 4. 类图
- 二、特点分析
- 三、适用场景
- 1. 股票价格监控系统
- 2. 物联网设备状态监控
- 3. 电商订单状态通知
- 四、Go语言实现示例
- 完整实现代码
- 执行结果
- 五、高级应用
- 1. 异步通知机制(参考网页10)
- 2. 事件过滤机制
- 六、与其他模式对比
- 七、实现建议
- 八、典型应用
一、核心概念
1. 定义
观察者模式是一种行为型设计模式,建立对象间的一对多依赖关系,当一个对象(主题)状态改变时,自动通知所有依赖对象(观察者)。其核心特点包括:
- 松耦合设计:主题与观察者通过接口交互()
- 动态订阅:运行时增减观察者()
- 广播通知:状态变化自动触发多对象更新()
2. 解决的问题
- 状态同步:多个对象需实时获取核心对象状态变化
- 事件驱动:构建解耦的事件响应系统()
- 资源监控:如CPU使用率报警()
3. 核心角色
角色 | 作用 |
---|---|
Subject | 维护观察者列表,定义注册/移除/通知方法() |
Observer | 定义更新接口,接收主题通知() |
ConcreteSubject | 实现具体状态管理和通知逻辑 |
ConcreteObserver | 实现业务响应逻辑 |
4. 类图
@startuml
interface Subject {
+ Register(Observer)
+ Remove(Observer)
+ Notify()
}
interface Observer {
+ Update()
}
class ConcreteSubject {
- state: int
+ SetState(int)
}
class ConcreteObserver {
+ Update()
}
Subject <|-- ConcreteSubject
Observer <|-- ConcreteObserver
ConcreteSubject "1" *-- "0..*" Observer
@enduml
二、特点分析
优点
- 解耦设计:主题与观察者无直接依赖()
- 动态扩展:支持运行时增减观察者()
- 事件驱动:适用于异步处理场景()
缺点
- 通知顺序:多个观察者的执行顺序不可控()
- 循环触发:不当设计可能引发循环调用()
- 性能开销:大量观察者时通知效率降低()
三、适用场景
1. 股票价格监控系统
// 股票主题
type StockSubject struct {
observers []Observer
price float64
}
func (s *StockSubject) Register(o Observer) {
s.observers = append(s.observers, o)
}
func (s *StockSubject) Notify() {
for _, o := range s.observers {
o.Update(s.price)
}
}
// 手机APP观察者
type MobileApp struct{}
func (m *MobileApp) Update(price float64) {
fmt.Printf("手机端收到股价更新: %.2f\n", price)
}
2. 物联网设备状态监控
// 设备状态主题
type DeviceMonitor struct {
observers []Observer
status string
}
func (d *DeviceMonitor) SetStatus(status string) {
d.status = status
d.Notify()
}
// 运维系统观察者
type OpsSystem struct{}
func (o *OpsSystem) Update(status string) {
if status == "ERROR" {
fmt.Println("触发告警:设备异常")
}
}
3. 电商订单状态通知
type OrderSubject struct {
observers []Observer
state string
}
func (o *OrderSubject) Ship() {
o.state = "SHIPPED"
o.Notify()
}
// 短信通知观察者
type SMSNotifier struct{}
func (s *SMSNotifier) Update(state string) {
if state == "SHIPPED" {
fmt.Println("发送物流短信通知")
}
}
四、Go语言实现示例
完整实现代码
package observer_demo
import (
"fmt"
"sync"
"time"
)
// OrderEvent 事件结构体
type OrderEvent struct {
OrderId string
Amount float64
PaymentTime time.Time
UserID string
}
// Observer 观察者接口
type Observer interface {
Handle(event OrderEvent) error
Name() string
}
// OrderSubject 主题接口
type OrderSubject interface {
Subscribe(observer Observer)
UnSubscribe(observer Observer)
Notify(event OrderEvent)
}
// OrderService 具体主题实现
type OrderService struct {
Observer sync.Map // 使用现成安全的Map存储观察者
wg sync.WaitGroup
}
func (s *OrderService) Subscribe(observer Observer) {
s.Observer.Store(observer.Name(), observer)
}
func (s *OrderService) UnSubscribe(observer Observer) {
s.Observer.Delete(observer.Name())
}
func (s *OrderService) Notify(event OrderEvent) {
s.Observer.Range(func(key, value interface{}) bool {
observer := value.(Observer)
s.wg.Add(1)
go func(obs Observer) {
defer s.wg.Done()
// 带超时控制的处理
done := make(chan struct{})
go func() {
defer close(done)
if err := retry(3, time.Second, func() error {
return obs.Handle(event)
}); err != nil {
fmt.Printf("[Error] %s处理失败: %v\n", obs.Name(), err)
}
}()
select {
case <-done:
fmt.Printf("[Info] %s处理完成\n", obs.Name())
case <-time.After(5 * time.Second):
fmt.Printf("[Error] %s处理超时\n", obs.Name())
}
}(observer)
return true
})
s.wg.Wait()
}
// 重试函数
func retry(attempts int, sleep time.Duration, fn func() error) error {
if err := fn(); err != nil {
if attempts--; attempts > 0 {
time.Sleep(sleep)
return retry(attempts, sleep, fn)
}
return err
}
return nil
}
// InventoryObserver 具体观察者实现
type InventoryObserver struct {
}
func (i *InventoryObserver) Name() string {
return "InventoryObserver"
}
func (i *InventoryObserver) Handle(event OrderEvent) error {
// 模拟库存扣减操作
fmt.Printf("库存系统:订单%s扣减库存,用户%s,金额%.2f\n",
event.OrderId, event.UserID, event.Amount)
return nil
}
// LogisticsObserver 具体观察者实现:物流业务
type LogisticsObserver struct {
}
func (l *LogisticsObserver) Name() string {
return "LogisticsObserver"
}
func (l *LogisticsObserver) Handle(event OrderEvent) error {
// 模拟物流操作
fmt.Printf("物流系统:订单%s发货,用户%s,金额%.2f\n",
event.OrderId, event.UserID, event.Amount)
return nil
}
// UserObserver 具体观察者实现,用户服务
type UserObserver struct {
}
func (u *UserObserver) Name() string {
return "UserObserver"
}
func (u *UserObserver) Handle(event OrderEvent) error {
// 模拟用户服务操作
fmt.Printf("用户服务:订单%s创建成功,用户%s,金额%.2f\n",
event.OrderId, event.UserID, event.Amount)
return nil
}
func test() {
// 创建主题
orderService := &OrderService{}
// 创建观察者
inventoryObserver := &InventoryObserver{}
logisticsObserver := &LogisticsObserver{}
userObserver := &UserObserver{}
// 注册观察者
orderService.Subscribe(inventoryObserver)
orderService.Subscribe(logisticsObserver)
orderService.Subscribe(userObserver)
// 模拟支付成功事件
event := OrderEvent{
OrderId: "20230303123456",
Amount: 2999.00,
PaymentTime: time.Now(),
UserID: "1001",
}
// 通知观察者
fmt.Println("=== 开始通知观察者 ===")
orderService.Notify(event)
fmt.Println("=== 所有通知处理完成 ===")
}
执行结果
=== RUN Test_test
=== 开始通知观察者 ===
物流系统:订单20230303123456发货,用户1001,金额2999.00
[Info] LogisticsObserver处理完成
用户服务:订单20230303123456创建成功,用户1001,金额2999.00
[Info] UserObserver处理完成
库存系统:订单20230303123456扣减库存,用户1001,金额2999.00
[Info] InventoryObserver处理完成
=== 所有通知处理完成 ===
--- PASS: Test_test (0.00s)
PASS
五、高级应用
1. 异步通知机制(参考网页10)
func (w *WeatherStation) asyncNotify() {
w.mu.Lock()
observers := make([]Observer, len(w.observers))
copy(observers, w.observers)
w.mu.Unlock()
var wg sync.WaitGroup
for _, o := range observers {
wg.Add(1)
go func(obs Observer) {
defer wg.Done()
obs.Update(w.temp)
}(o)
}
wg.Wait()
}
2. 事件过滤机制
type SmartObserver struct {
lastTemp float64
}
func (s *SmartObserver) Update(temp float64) {
if math.Abs(temp-s.lastTemp) > 1.0 {
fmt.Println("温度变化超过1度")
s.lastTemp = temp
}
}
六、与其他模式对比
模式 | 核心区别 | 典型场景 |
---|---|---|
中介者模式 | 通过中介协调多对象交互 | 复杂对象间通信 |
责任链模式 | 请求沿链传递 vs 广播通知 | 审批流程处理 |
发布订阅 | 引入消息代理解耦更彻底() | 分布式系统消息传递 |
七、实现建议
- 线程安全:使用
sync.Mutex
保证并发安全() - 批量通知:使用
copy
避免通知过程中列表变更(见示例) - 性能优化:对于大量观察者采用批处理或异步通知()
- 防止泄漏:及时移除无效观察者()
八、典型应用
- GUI事件处理:如按钮点击事件监听()
- 微服务配置中心:配置变更通知服务集群()
- 游戏引擎:玩家状态变化触发多系统响应()
通过这种设计模式,可以构建出松耦合、易扩展的事件驱动系统。在实际Go开发中,结合channel特性还能实现更高效的观察者模式变体。