设计模式——观察者模式

什么是观察者模式?

又叫发布-订阅模式(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
*/

优点

  • 观察者和被观察者是抽象耦合的;
  • 建立了一套触发机制;

缺点

  • 如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间;

  • 如果观察者和观察目标间有循环依赖,可能导致系统崩溃;

  • 没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的。

使用场景

  • 关联行为场景;
  • 事件多级触发场景;
  • 跨系统的消息变换场景,如消息队列的处理机制。

注意

  • 避免循环引用;
  • 如果顺序执行,某一观察者错误会导致系统卡壳,一般采用异步方式。
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容