什么是观察者模式?
又叫发布-订阅模式(Publish/Subscribe),定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新。
实现
// 事件
type Event struct {
Data int
}
type Observer interface {
NotifyCallback(event Event)
}
type Subject interface {
AddListener(observer Observer)
RemoveListener(observer Observer)
Notify(event Event)
}
type EventObserver struct {
ID int
Time time.Time
}
type EventSubject struct {
Observers sync.Map
}
func (this EventObserver) NotifyCallback(event Event) {
fmt.Printf("Received:%d after %v\n", event.Data, time.Since(this.Time))
}
func (this *EventSubject) AddListener(observer Observer) {
this.Observers.Store(observer, struct{}{})
}
func (this *EventSubject) RemoveListener(observer Observer) {
this.Observers.Delete(observer)
}
func (this *EventSubject) Notify(event Event) {
this.Observers.Range(func(key, value interface{}) bool {
if key == nil {
return false
}
key.(Observer).NotifyCallback(event)
return true
})
}
func Fib(n int) chan int {
out := make(chan int)
go func() {
defer close(out)
for i, j := 0, 1; i < n; i, j = i+j, i {
out <- i
}
}()
return out
}
func TestFib(t *testing.T) {
//for x := range Fib(10) {
// fmt.Println(x)
//}
event := EventSubject{Observers:sync.Map{}}
obs1 := EventObserver{ID:1, Time:time.Now()}
obs2 := EventObserver{ID:2, Time:time.Now()}
event.AddListener(obs1)
event.AddListener(obs2)
event.RemoveListener(obs1)
for x:= range Fib(10) {
event.Notify(Event{Data:x})
}
}
/*
=== RUN TestFib
Received:0 after 0s
Received:1 after 0s
Received:1 after 0s
Received:2 after 0s
Received:3 after 0s
Received:5 after 0s
Received:8 after 0s
--- PASS: TestFib (0.00s)
PASS
*/
优点
- 观察者和被观察者是抽象耦合的;
- 建立了一套触发机制;
缺点
-
如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间;
-
如果观察者和观察目标间有循环依赖,可能导致系统崩溃;
-
没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的。
使用场景
- 关联行为场景;
- 事件多级触发场景;
- 跨系统的消息变换场景,如消息队列的处理机制。
注意
- 避免循环引用;
- 如果顺序执行,某一观察者错误会导致系统卡壳,一般采用异步方式。
网友评论