go 设计模式之观察者模式

观察者模式

观察者模式定义了一系列对象之间的一对多关系。

当一个对象改变状态时,其他依赖者都会收到通知。

模型说明

1.设计要点

设计观察者模式的程序时要注意以下几点。 (1)要明确谁是观察者谁是被观察者。一般观察者与被观察者之间是多对一的关系,一个被观察者对象可以有多个观察者对象。 (2)被观察者对象在发送广播通知时,无须指定具体的观察者对象,观察者对象可自己决定是否订阅被观察者对象的通知。 (3)被观察者至少有三个方法:添加观察者、移除观察者、通知观察者的方法。观察者至少有一个方法:更新方法,即更新当前的内容,做出相应的处理。

2.推模型和拉模型

观察者模式根据其侧重的功能可分为推模型和拉模型。 (1)推模型 被观察者对象向观察者对象推送主题的详细信息,不管观察者是否需要,推送的信息通常是主题对象的全部或部分数据。一般在这种模型的实现中会将被观察者对象中的全部或部分信息通过作为观察者的更新方法的参数传递给观察者。 (2)拉模型 被观察者对象在通知观察者时,只传递少量信息。如果观察者需要更详细的信息,由观察者主动到被观察者对象中获取,相当于观察者从被观察者对象中拉取数据。

推模型被认为是更正确的做法。

优缺点

1.优点

  • 开闭原则。 你无需修改被观察者代码就能引入新的观察者。
  • 你可以在运行时建立对象之间的联系。

2.缺点

  • 观察者的通知顺序是随机的。

使用场景

  • 当一个对象的状态改变时,需要联动多个对象进行状态变更/显示时。
  • 对象仅需要将自己的更新通知给其他对象而不需要知道其他对象的细节,如消息推送等。

参考代码

subject.go

go 复制代码
package main

type Subject interface {
	RegisterObserver(name string, o Observer)
	RemoveObserve(name string)
	Notify()
}

type PeopleSubject struct {
	Observers map[string]Observer
	Question  string
}

func (s *PeopleSubject) RegisterObserver(name string, o Observer) {
	if s.Observers == nil {
		s.Observers = make(map[string]Observer)
	}
	s.Observers[name] = o
}

func (s *PeopleSubject) RemoveObserve(name string) {
	delete(s.Observers, name)
}

func (s *PeopleSubject) Notify() {
	for _, o := range s.Observers {
		o.Answer()
	}
}

func (s *PeopleSubject) SetQuestion(question string) {
	s.Question = question
	s.Notify()
}

observer.go

go 复制代码
package main

import "fmt"

type Observer interface {
	Answer()
}

type AngelObserver struct{}

func (o *AngelObserver) Answer() {
	fmt.Println("fuck off")
}

type DemonObserver struct{}

func (o *DemonObserver) Answer() {
	fmt.Println("go for it!")
}

main.go

go 复制代码
package main

var (
	// PeopleSubject 实现 Subject 接口
	_ Subject = (*PeopleSubject)(nil)
)

func main() {
	s := new(PeopleSubject)
	s.RegisterObserver("angle", new(AngelObserver))
	s.RegisterObserver("demon", new(DemonObserver))
	s.SetQuestion("what should i do?")
}

output:

go 复制代码
fuck off
go for it!

Q&A

Q:依赖是如何产生的?

A:因为主题是真正拥有数据的人,观察者是主题的依赖者,在数据变化时更新,这样比起让许多对象控制同一份数据来,可以得到更干净的 OO 设计。

相关推荐
紧跟先前的步伐1 小时前
Go AI Agent 实战 24|工具系统工程化收尾与阶段验收
人工智能·ai·golang·1024程序员节
日日大王学编程3 小时前
#Feed 流项目复盘:Redis 时间线缓存与 Outbox 消息可靠性设计
golang·1024程序员节
北冥you鱼10 小时前
Go 语言 CRUD 实战:从接口设计到真实业务场景
开发语言·后端·golang
利威尔xu13 小时前
Go IM 源码实战(11):token 只是个 HASH,多端互踢的顺序错了就踢错人
后端·微服务·面试·架构·golang
microrain13 小时前
SagooIoT 把协议解析和消息通知都放进了独立进程
物联网·golang·插件·sagooiot
北冥you鱼14 小时前
Go 语言 GORM 使用 Preload:从关联查询到嵌套预加载的完整实践
开发语言·jvm·golang
microrain14 小时前
把规则链存成文件之后,上线一条规则只需改一个字段
物联网·golang·规则引擎·sagooiot
是2的10次方啊15 小时前
设计模式与生活⑦:你打的车,隔着一个平台
设计模式
geovindu16 小时前
rust: Read-Write Lock Pattern
开发语言·后端·设计模式·rust·读写锁模式·同步型模式
SEO_juper17 小时前
Go 站点地图生成器:从首页爬全站,一键生成 sitemap.xml
xml·开发语言·人工智能·golang·node.js·seo·外贸独立站