GO设计模式——21、观察者模式(行为型)

目录

[观察者模式(Observer Pattern)](#观察者模式(Observer Pattern))

观察者模式的核心角色:

优缺点

使用场景

注意事项

代码实现


观察者模式(Observer Pattern)

观察者模式(Observer Pattern)定义了对象间的一种一对多的依赖关系,使得当一个对象状态发生改变时,所有依赖于它的对象都可以自动得到通知并且被更新。观察者模式是一种一对多的关系,可以有任意个(1个或多个)观察者对象同时监听(观察)某一个对象。

观察者模式核心角色

  • 主题(Subject):负责维护一组观察者,并在状态改变时通知观察者。也称为被观察者或可观察者,它是具有状态的对象,并维护着一个观察者列表。主题提供了添加、删除和通知观察者的方法。
  • 观察者(Observer):观察者是接收主题通知的对象。观察者需要实现一个更新方法,当收到主题的通知时,调用该方法进行更新操作。
  • 具体主题(Concrete Subject):具体主题是主题的具体实现类。它维护着观察者列表,并在状态发生改变时通知观察者。
  • 具体观察者(Concrete Observer):具体观察者是观察者的具体实现类。它实现了更新方法,定义了在收到主题通知时需要执行的具体操作。

优缺点

(1)优点:

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

(2)缺点:

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

使用场景

  • 一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。
  • 一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。
  • 一个对象必须通知其他对象,而并不知道这些对象是谁。
  • 需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象......,可以使用观察者模式创建一种链式触发机制。

注意事项

  • 避免循环引用。
  • 如果顺序执行,某一观察者错误会导致系统卡壳,一般采用异步方式。

代码实现

Go 复制代码
package main

import "fmt"

// 新闻发布系统,用户可以订阅感兴趣的新闻主题,并在新闻发布时收到通知。
// 希望能够实现一个观察者模式,使订阅者能够接收到相关新闻的通知。

// 主题接口
type Subject interface {
    Register(observer Observer)
    Unregister(observer Observer)
    Notify()
}

// 具体主题
type NewsSubject struct {
    observers []Observer
    news      string
}

// 注册
func (n *NewsSubject) Register(observer Observer) {
    n.observers = append(n.observers, observer)
}

// 注销
func (n *NewsSubject) Unregister(observer Observer) {
    for i, o := range n.observers {
       if o == observer {
          n.observers = append(n.observers[:i], n.observers[i+1:]...)
          break
       }
    }
}

// 通知观察者
func (n *NewsSubject) Notify() {
    for _, observer := range n.observers {
       observer.Update(n)
    }
}

func (n *NewsSubject) SetNews(news string) {
    n.news = news
    n.Notify()
}

// 观察者接口
type Observer interface {
    Update(subject Subject)
}

// 具体观察者
type Subscriber struct {
    name string
}

func (s *Subscriber) Update(subject Subject) {
    newsSubject := subject.(*NewsSubject)
    fmt.Printf("[%s] 收到新闻通知:%s\n", s.name, newsSubject.news)
}

// 客户端代码
func main() {
    subject := &NewsSubject{}

    subscriber1 := &Subscriber{name: "订阅者1"}
    subject.Register(subscriber1)

    subscriber2 := &Subscriber{name: "订阅者2"}
    subject.Register(subscriber2)

    subject.SetNews("新闻1发布了")
    subject.SetNews("新闻2发布了")

    subject.Unregister(subscriber1)

    subject.SetNews("新闻3发布了")
}
相关推荐
小白不太白9502 小时前
设计模式之 模板方法模式
java·设计模式·模板方法模式
色空大师2 小时前
23种设计模式
java·开发语言·设计模式
闲人一枚(学习中)2 小时前
设计模式-创建型-建造者模式
java·设计模式·建造者模式
博风3 小时前
设计模式:6、装饰模式(包装器)
设计模式
A_cot3 小时前
理解设计模式与 UML 类图:构建稳健软件架构的基石
microsoft·设计模式·简单工厂模式·工厂方法模式·uml
君败红颜3 小时前
设计模式之创建模式篇
设计模式
hummhumm3 小时前
第 22 章 - Go语言 测试与基准测试
java·大数据·开发语言·前端·python·golang·log4j
hummhumm3 小时前
第 28 章 - Go语言 Web 开发入门
java·开发语言·前端·python·sql·golang·前端框架
YMWM_4 小时前
第一章 Go语言简介
开发语言·后端·golang
hummhumm5 小时前
第 25 章 - Golang 项目结构
java·开发语言·前端·后端·python·elasticsearch·golang