go语言设计模式 - 观察者模式 | 青训营笔记

108 阅读3分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 10 天

go语言设计模式 - 观察者模式

1. 介绍

观察者模式是用于建立一种对象与对象之间的依赖关系,一个对象发生改表时将自动通知其他对象,其他对象将相应的作出反应。在观察者模式中,发生改变的对象称为观察目标,而被通知的对象称为观察者,一个观察目标可以对应多个观察者,而且这些观察者之间没有任何相互联系,可以根据需要增加和删除观察者,使得系统更易于扩展。

2. 类图

image-20230126143605617

Subject(被观察者或目标,抽象主题):被观察的对象。当需要被观察的状态发生变化时,需要通知队列中所有的观察者对象。Subject需要维持(添加,删除,通知)一个观察者对象的队列列表。

ConcreteSubject(具体被观察者或目标,具体主题):被观察者的具体实现。包含一些基本的属性状态及其他操作。

Observer(观察者):接口或抽象类。当Subject的状态发生变化时,Observer对象将通过一个callback函数得到通知。

ConcreteObserver(具体观察者):观察者的具体实现,得到通知后将完成一些具体的业务逻辑处理。

3. 代码

package main
​
import "fmt"
​
// =========== 抽象层 ================
type Listener interface {
    OnTeacherComming() // 观察者得到通知后需要触发的动作
}
​
type Notifier interface {
    AddListenner(listener Listener)
    RemoveListener(listener Listener)
    Notify()
}
​
// =========== 实现层 =================
// 观察者具体的学生
type StuZhangSan struct {
    Badthing string
}
​
func (s *StuZhangSan) DoBadThing() {
    fmt.Println("张三 正在", s.Badthing)
}
​
func (s *StuZhangSan) OnTeacherComming() {
    fmt.Println("张三 停止", s.Badthing)
}
​
type StuZhanSi struct {
    Badthing string
}
​
func (s *StuZhanSi) DoBadThing() {
    fmt.Println("张四 正在", s.Badthing)
}
​
func (s *StuZhanSi) OnTeacherComming() {
    fmt.Println("张四 停止", s.Badthing)
}
​
type StuWang5 struct {
    Badthing string
}
​
func (s *StuWang5) DoBadThing() {
    fmt.Println("王五 正在", s.Badthing)
}
​
func (s *StuWang5) OnTeacherComming() {
    fmt.Println("王5 停止 ", s.Badthing)
}
​
// 统治者班长
type ClassMonitor struct {
    ListenerList []Listener // 需要通知的全部观察者集合
}
​
func (m *ClassMonitor) AddListenner(listener Listener) {
    m.ListenerList = append(m.ListenerList, listener)
}
​
func (m *ClassMonitor) RemoveListener(listener Listener) {
    for index, l := range m.ListenerList {
        // 找到删除的元素位置
        if listener == l {
            // 将删除的元素的前后位置链接起来
            m.ListenerList = append(m.ListenerList[:index], m.ListenerList[index+1:]...)
            break
        }
    }
}
​
func (m *ClassMonitor) Notify() {
    for _, listener := range m.ListenerList {
        listener.OnTeacherComming() // 多态现象
    }
}
​
// 业务逻辑
func main() {
    s1 := &StuZhangSan{
        Badthing: "抄作业",
    }
​
    s2 := &StuZhanSi{
        Badthing: "玩王者荣耀",
    }
​
    s3 := &StuWang5{
        Badthing: "看赵4玩王者荣耀",
    }
​
    classMonitor := new(ClassMonitor)
    classMonitor.AddListenner(s1)
    classMonitor.AddListenner(s2)
    classMonitor.AddListenner(s3)
​
    fmt.Println("上课了, 但是老师没有来, 学生都在忙自己的事情")
    s1.DoBadThing()
    s2.DoBadThing()
    s3.DoBadThing()
​
    fmt.Println("这时候老师来了")
​
    classMonitor.Notify()
​
}
​

4. 观察者 模式优缺点

优点:

  1. 观察者模式可以实现表示层和数据逻辑层的分离,定义了稳定的消息更新传递机制,并抽象了更新接口,使得可以有各种各样不同的表示层充当具体观察者角色。
  2. 观察者模式在观察目标和观察者之间建立一个抽象的耦合。观察目标只需要维持一个抽象观察者的集合,无须了解其具体观察者。由于观察目标和观察者没有紧密的耦合在一起,因此它们属于不同的抽象化层次。
  3. 观察者模式支持广播通信,观察目标会向所有已注册的观察对象发送通知,简化了一对多系统设计的难度。
  4. 观察者模式满足“开闭原则”的要求,增加新的具体观察者无需修改原有系统代码,在具体观察者与观察目标之间不存在关联关系的情况下,增加新的观察目标也很方便。

缺点:

  1. 如果一个观察目标有很多直接或间接观察者,将所有的观察者都通知到会花费很多时间。
  2. 如果在观察者和观察目标之间存在循环依赖,观察目标会触发他们之间进行循环调用,可能导致系统崩溃。
  3. 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。