模式定义

定义了对象之间的一对多依赖,让多个观察者对象同时监听某一个主题对象,当主题对象发生变化时,它的所有依赖者都会收到通知并更新

类图

image-20210719214549418.png

应用场景

当更改一个对象的状态可能需要更改其他对象,并且实际的对象事先未知或动态更改时,使用观察者模式

优点

1.符合开闭原则

2.可以在运行时建立对象之间的关系

要点总结

  • 使用面向对象的抽象,Observe模式使得我们可以独立地改变目标与观察者,从而使二者之间的依赖关系达到松耦合
  • 目标发送通知时,无需指定观察者,通知(可以携带通知信息作为参数)会自动传播
  • 观察者自己解决是否需要订阅通知,目标对象对此一无所知
  • Observer模式是基于事件的UI框架中非常常用的设计模式,也是MVC模式的一个重要组成部分

Go语言代码实现

工程目录

image-20210706220132103.png

observe.go

package Observer

import (
   "fmt"
   "sync"
   "time"
)

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 (e eventObserver) NotifyCallback(event Event) {
   fmt.Printf("Recieved:%d after %v\n", event.Data, time.Since(e.Time))
}

func (e *eventSubject) AddListener(obs Observer) {
   e.Observers.Store(obs, struct{}{})
}

func (e *eventSubject) RemoveListener(obs Observer) {
   e.Observers.Delete(obs)
}

func (e *eventSubject) Notify(event Event) {
   e.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
}

observer_test.go

package Observer

import (
   "sync"
   "testing"
   "time"
)

func TestFib(t *testing.T) {
   //for x := range Fib(10) {
   // fmt.Println(x)
   //}

   n := eventSubject{Observers: sync.Map{}}
   obs1 := eventObserver{ID: 1, Time: time.Now()}
   obs2 := eventObserver{ID: 2, Time: time.Now()}

   n.AddListener(obs1)
   n.AddListener(obs2)

   for x := range Fib(10) {
      n.Notify(Event{Data: x})
   }
}

Yuan_sr
18 声望6 粉丝