新闻中心
如何在Golang中实现观察者模式_Golang观察者模式实现方法汇总
Go语言中实现观察者模式有四种常见方式:1. 基于接口的标准模式,通过Subject和Observer接口实现松耦合;2. 使用channel实现异步通知,利用goroutine和channel进行非阻塞消息广播;3. 利用闭包简化观察者,以函数类型封装更新逻辑;4. 泛型支持的通用模式(Go 1.18+),可传递任意类型数据。选择方式需根据场景:标准接口适合结构清晰的系统,channel适合高并发,闭包适合轻量逻辑,泛型适合多类型数据传递。关键在于解耦主题与观察者,并注意并发安全与注销时的切片操作安全。

在Go语言中实现观察者模式,核心是定义一个主题(Subject)和多个观察者(Observer),当主题状态发生变化时,自动通知所有注册的观察者。这种设计模式常用于事件处理系统、消息订阅等场景。以下是几种常见的Golang实现方式。
1. 基于接口的标准观察者模式
通过接口定义主题和观察者的行为,实现松耦合结构。
定义观察者和主题接口:
type Observer interface {
Update(message string)
}
<p>type Subject interface {
Register(observer Observer)
Deregister(observer Observer)
Notify(message string)
}</p>实现具体主题:
type ConcreteSubject struct {
observers []Observer
}
<p>func (s *ConcreteSubject) Register(observer Observer) {
s.observers = append(s.observers, observer)
}</p><p>func (s *ConcreteSubject) Deregister(observer Observer) {
for i, obs := range s.observers {
if obs == observer {
s.observers = append(s.observers[:i], s.observers[i+1:]...)
break
}
}
}</p><p>func (s *ConcreteSubject) Notify(message string) {
for _, observer := range s.observers {
observer.Update(message)
}
}</p>实现具体观察者:
type ConcreteObserver struct {
name string
}
<p>func (o *ConcreteObserver) Update(message string) {
fmt.Printf("[%s] 收到消息: %s\n", o.name, message)
}</p>使用示例:
subject := &ConcreteSubject{}
observerA := &ConcreteObserver{name: "A"}
observerB := &ConcreteObserver{name: "B"}
<p>subject.Register(observerA)
subject.Register(observerB)</p><p>subject.Notify("系统更新了")
// 输出:
// [A] 收到消息: 系统更新了
// [B] 收到消息: 系统更新了</p>2. 使用channel实现异步通知
利用Go的并发特性,通过channel实现非阻塞的消息广播,适合高并发场景。
PictoGraphic
AI驱动的矢量插图库和插图生成平台
133
查看详情
type AsyncSubject struct {
register chan Observer
deregister chan Observer
message chan string
observers map[Observer]bool
}
<p>func NewAsyncSubject() *AsyncSubject {
subject := &AsyncSubject{
register: make(chan Observer),
deregister: make(chan Observer),
message: make(chan string),
observers: make(map[Observer]bool),
}
go subject.start()
return subject
}</p><p>func (s *AsyncSubject) start() {
for {
select {
case observer := <
;-s.register:
s.observers[observer] = true
case observer := <-s.deregister:
delete(s.observers, observer)
case msg := <-s.message:
for observer := range s.observers {
go observer.Update(msg) // 异步通知
}
}
}
}</p><p>func (s *AsyncSubject) Register(observer Observer) {
s.register <- observer
}</p><p>func (s *AsyncSubject) Deregister(observer Observer) {
s.deregister <- observer
}</p><p>func (s *AsyncSubject) Notify(message string) {
s.message <- message
}</p>这种方式将注册、注销和通知操作放入goroutine中处理,避免主线程阻塞。
3. 利用闭包简化观察者定义
如果不需要复杂的结构体,可以用函数类型和闭包快速实现轻量级观察者。
type Callback func(message string)
<p>type FuncObserver struct {
callback Callback
}</p><p>func (f *FuncObserver) Update(message string) {
f.callback(message)
}</p><p>// 使用示例
observer := &FuncObserver{
callback: func(msg string) {
fmt.Println("闭包收到:", msg)
},
}</p>这种方式适合逻辑简单的监听场景,代码更简洁。
4. 泛型支持的通用观察者模式(Go 1.18+)
使用泛型可以让观察者模式支持不同类型的数据传递。
type GenericObserver[T any] interface {
OnEvent(data T)
}
<p>type GenericSubject[T any] struct {
observers []GenericObserver[T]
}</p><p>func (s *GenericSubject[T]) Attach(obs GenericObserver[T]) {
s.observers = append(s.observers, obs)
}</p><p>func (s *GenericSubject[T]) Notify(data T) {
for _, obs := range s.observers {
obs.OnEvent(data)
}
}</p>可以用于传递结构体、数字等任意类型数据。
基本上就这些常见实现方式。选择哪种取决于你的需求:标准接口适合清晰结构,channel适合高并发,闭包适合轻量逻辑,泛型适合类型多样的场景。关键是理解主题与观察者之间的解耦关系。不复杂但容易忽略细节,比如注销时的切片操作安全性和并发访问控制。实际项目中建议结合sync.Mutex保护共享状态。
以上就是如何在Golang中实现观察者模式_Golang观察者模式实现方法汇总的详细内容,更多请关注其它相关文章!
# 正则表达式
# 如何专卖旧书的网站推广
# 辽宁公司网站建设企业
# 贵州抖音seo优化案例
# 大庆seo服务必看
# 龙泉营销推广
# 博客排名seo顾问
# seo优化软文工具
# SEO优化工具收纳文案
# 西藏外文网站推广
# 四平网站综合优化
# 四种
# 解决问题
# go
# 几种
# 中文网
# 相关文章
# 可以用
# 不需要
# 多个
# 如何在
# 并发访问
# app
# go语言
# golang
相关栏目:
【
科技资讯46185 】
【
网络学院92790 】
相关推荐:
神庙逃亡小游戏在线玩 神庙逃亡小游戏入口
高德地图总提示网络异常怎么办 高德地图离线导航设置与网络排查方法
css滚动区域卡顿如何改善_css滚动问题用will-change优化渲染
曝R星经典之作开发图 设计简陋但信息密集!
Safari自带网页翻译功能怎么用 无需插件轻松看懂外文网站【方法】
Lar*el递归关系中排除子孙节点的策略
Tailwind CSS line-clamp 布局问题解析与修复指南
Gmail邮箱申请注册直达_Gmail邮箱免费注册PC版官网入口2025
qq浏览器如何查看和导出已保存的密码 qq浏览器密码管理器数据备份教程
豆包手机助手发布技术预览版:直接嵌入手机系统!努比亚样机发售
css元素hover动画延迟生效怎么办_使用animation-delay调整触发时间
uc浏览器网页版入口 uc浏览器网页版最新网址
大麦的“候补”是什么意思 大麦候补购票规则【详解】
网站内容防复制粘贴的实现策略与局限性
TikTok评论显示延迟如何处理 TikTok评论刷新优化方法
在J*a中如何开发简易仓库管理与库存统计_仓库管理库存统计项目实战解析
Angular中父组件异步更新子组件复选框状态的实践指南
2025AO3夸克浏览器通道_AO3手机HTTPS安全入口分享
顺丰快递查询系统 官方正版查询入口
J*aScript 字符串标签转换:使用正则表达式高效替换
搜狗浏览器如何使用密码生成器创建强密码 搜狗浏览器内置密码安全工具
如何解决电商平台定制报价请求的“黑洞”问题,SprykerQuoteRequest模块助你提升客户体验与销售效率
jQuery Mask 插件中实现电话号码固定前导零的教程
Vue.js 图片显示异常排查:理解应用挂载范围与DOM ID唯一性
Typer应用中灵活处理命令行参数的令牌化与解析
如何将一个大型PHP应用拆分为多个Composer包_微服务与模块化架构的Composer实践
支付宝如何设置安全保护_支付宝安全设置的全面教程
解决移动端滚动问题的overflow属性应用指南
Win11 USB传输速度慢怎么解决 Win11 USB驱动更新与设置
智慧团建扫码登录入口 智慧团建扫码登录入口官网版
Go与Ruby之间实现AES加密互通:CFB模式下的密钥长度匹配策略
反效果?《战地6》免费试玩开启后玩家数不升反降
在J*a中如何使用Exception包装底层异常_异常包装与信息传递方法说明
excel怎么制作工资条 excel快速生成工资条的方法
Win11截图该按哪些键 Win11截屏完整流程解析【教程】
在python-socketio事件处理器中安全访问Flask应用上下文
CSS子选择器:如何区分并样式化嵌套列表的子层级
为什么我的微信朋友圈看不到别人的更新_微信朋友圈更新显示异常解决方法
React/Next.js中实现列表项的动态移动与状态管理:兼论唯一键的重要性
Lar*el如何生成PDF或Excel文件_Lar*el文档导出工具与使用教程
漫蛙manwa2最新登录网址_漫蛙manwa2手机网页版入口
Golang如何处理RPC请求负载均衡_Golang RPC请求负载均衡策略与实践
AO3最新官网入口公告_2025AO3镜像站实时查询方法
QQ邮箱官方网页版登录 QQ邮箱个人邮箱快速访问
Angular中单选按钮的正确使用与常见陷阱解析
夸克浏览器网页版最新地址 夸克浏览器官方入口合集
Python getattr() 异常处理深度解析:避免程序意外退出
Excel文件在线转换快速入口 Excel在线格式转换网站
我的世界官方游戏入口 我的世界官网平台直达链接
Go语言中的*string:深入理解字符串指针


2025-11-23
浏览次数:次
返回列表
;-s.register:
s.observers[observer] = true
case observer := <-s.deregister:
delete(s.observers, observer)
case msg := <-s.message:
for observer := range s.observers {
go observer.Update(msg) // 异步通知
}
}
}
}</p><p>func (s *AsyncSubject) Register(observer Observer) {
s.register <- observer
}</p><p>func (s *AsyncSubject) Deregister(observer Observer) {
s.deregister <- observer
}</p><p>func (s *AsyncSubject) Notify(message string) {
s.message <- message
}</p>