设计模式-15-观察者模式

观察者模式是一种行为设计模式,允许你定义一种订阅机制,可在对象事件发生时通知多个“观察” 该对象的其他对象

逻辑结构

在观察者模式中,有两个角色:

  • Subject(目标): 定义了对象之间的一对多依赖关系。当其状态发生改变时,通知所有注册的观察者对象。
  • Observer(观察者): 定义了接收到目标通知时所执行的操作
image-20230721223407590

ConcreteSubject 类与 Observer 接口之间有关联关系。意味着 ConcreteSubject 类通过 RegisterObserverRemoveObserver 方法来管理多个 Observer 观察者对象

代码实现

代码路径:https://github.com/XBoom/DesignPatterns/tree/main/14_Observer

  1. 首先,定义观察者接口,表示收到目标通知触发更新的接口

    1
    2
    3
    4
    // Observer 观察者接口
    type Observer interface {
    Update(message string)
    }
  2. 其次,定义目标接口,每个目标都可以添加、删除观察者,并可以通知观察者

    1
    2
    3
    4
    5
    6
    // Subject 被观察者接口
    type Subject interface {
    RegisterObserver(observer Observer)
    RemoveObserver(observer Observer)
    NotifyObservers()
    }
  3. 接着,实现观察者,也就是收到通知之后触发的业务

    1
    2
    3
    4
    5
    6
    7
    8
    // ConcreteObserver 具体观察者
    type ConcreteObserver struct {
    name string
    }

    func (co *ConcreteObserver) Update(message string) {
    fmt.Printf("[%s] 收到消息:%s\n", co.name, message)
    }
  4. 最后,实现目标,目标通知注册的每个观察者。所以目标中有存储观察者们

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    // ConcreteSubject 具体被观察者
    type ConcreteSubject struct {
    observers []Observer //观察者们
    }

    // RegisterObserver 注册观察者
    func (cs *ConcreteSubject) RegisterObserver(observer Observer) {
    cs.observers = append(cs.observers, observer)
    }

    // RemoveObserver 删除观察者
    func (cs *ConcreteSubject) RemoveObserver(observer Observer) {
    index := -1
    for i, obs := range cs.observers {
    if obs == observer {
    index = i
    break
    }
    }
    if index >= 0 {
    cs.observers = append(cs.observers[:index], cs.observers[index+1:]...)
    }
    }

运行逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//定义观察者与被观察者
subject := &ConcreteSubject{}

observer1 := &ConcreteObserver{name: "Observer1"}
observer2 := &ConcreteObserver{name: "Observer2"}

//对象注册观察者
subject.RegisterObserver(observer1)
subject.RegisterObserver(observer2)

//通知观察者
subject.NotifyObservers("Hello, observers!")

//删除一个观察者
subject.RemoveObserver(observer1)

//再次通知观察者
subject.NotifyObservers("Hi, observers!")

运行结果

1
2
3
[Observer1] 收到消息:Hello, observers!
[Observer2] 收到消息:Hello, observers!
[Observer2] 收到消息:Hi, observers!

总结

  • 当一个对象状态的改变需要改变其他对象,或实际对象是事先未知的或动态变化的时
  • 当应用中的一些对象必须观察其他对象时,但仅能在有限时间内或特定情况下使用
  • 开闭原则无需修改发布者代码就能引入新的订阅者类 (如果是发布者接口则可轻松引入发布者类),channel 也存在类似功能。
  • 由于主题和观察者之间的关系是通过接口而不是具体实现建立的,因此它们可以在不同的上下文中重复使用

参考链接

  1. https://refactoringguru.cn/design-patterns/observer
  2. https://lailin.xyz/post/observer.html