GoLang设计模式13 - 观察者模式
观察者模式是一种行为型设计模式。这种模式允许一个实例(可以称为目标对象)发布各种事件(event)给其他实例(观察者)。这些观察者会对目标对象进行订阅,这样每当目标对象发生变化时,观察者就会收到事件(event)通知。
来看个例子:在电商网站经常会有各种商品脱销,假如有顾客已经在关注这些商品,这些商品的脱销就会对他们产生不好的体验。如果顾客还想买这些商品,那么通常有如下解决方案:
- 顾客以一定的频率检查这些商品是否在售
- 电商平台将所有的上架的商品信息定期推送给用户
- 顾客只订阅他所关注的特定商品的信息,当这些商品再次上架时他们会收到通知;多个顾客可以订阅同一个商品的信息
选项3是最为可行的一种方案。这也正是观察者模式所能做到的事情。观察者模式的核心组件为:
- Subject : 目标对象,是有变化发生时就会发布相关事件的实例
- Observer : 观察者,订阅目标对象的信息,会收到一些特定事件的通知
通常,Subject和Observer会被定义为接口,真正使用的是它们二者的具体实现。
UML类图如下:

下面是一个示例代码:
observer.go:
type observer interface {
update(string)
getID() string
}
subject.go:
type subject interface {
register(Observer observer)
deregister(Observer observer)
notifyAll()
}
item.go:
import "fmt"
type item struct {
observerList []observer
name string
inStock bool
}
func newItem(name string) *item {
return &item{
name: name,
}
}
func (i *item) updateAvailability() {
fmt.Printf("Item %s is now in stock\n", i.name)
i.inStock = true
i.notifyAll()
}
func (i *item) register(o observer) {
i.observerList = append(i.observerList, o)
}
func (i *item) deregister(o observer) {
i.observerList = removeFromSlice(i.observerList, o)
}
func (i *item) notifyAll() {
for _, observer := range i.observerList {
observer.update(i.name)
}
}
func removeFromSlice(observerList []observer, observerToRemove observer) []observer {
observerListLength := len(observerList)
for i, observer := range observerList {
if observerToRemove.getID() == observer.getID() {
observerList[observerListLength-1], observerList[i] = observerList[i], observerList[observerListLength-1]
return observerList[:observerListLength-1]
}
}
return observerList
}
customer.go:
import "fmt"
type customer struct {
id string
}
func (c *customer) update(itemName string) {
fmt.Printf("Sending email to customer %s for item %s\n", c.id, itemName)
}
func (c *customer) getID() string {
return c.id
}
在上面的代码中item是subject的实现,customer是observer实现。
看下场景类main.go:
func main() {
shirtItem := newItem("GoLang Design Patterns")
observerFirst := &customer{id: "robin@zhyea.com"}
observerSecond := &customer{id: "golang@zhyea.com"}
shirtItem.register(observerFirst)
shirtItem.register(observerSecond)
shirtItem.updateAvailability()
}
执行后输出内容为:
Item GoLang Design Patterns is now in stock
Sending email to customer robin@zhyea.com for item GoLang Design Patterns
Sending email to customer golang@zhyea.com for item GoLang Design Patterns
代码已上传至GitHub: zhyea / go-patterns / observer-pattern
END!
GoLang设计模式13 - 观察者模式的更多相关文章
- 乐在其中设计模式(C#) - 观察者模式(Observer Pattern)
原文:乐在其中设计模式(C#) - 观察者模式(Observer Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 观察者模式(Observer Pattern) 作者:weba ...
- 设计模式之观察者模式(Observable与Observer)
设计模式之观察者模式(Observable与Observer) 好久没有写博客啦,之前看完了<设计模式之禅>也没有总结一下,现在回忆一下设计模式之观察者模式. 1.什么是观察者模式 简单情 ...
- 8.5 GOF设计模式四: 观察者模式Observer
GOF设计模式四: 观察者模式Observer 现实中遇到的问题 当有许多不同的客户都对同一数据源感兴趣,对相同的数据有不同的处理方式,该如 何解决?5.1 定义: 观察者模式 观察者模式 ...
- Golang设计模式—简单工厂模式(Simple Factory Pattern)
Golang设计模式--简单工厂模式 背景 假设我们在做一款小型翻译软件,软件可以将德语.英语.日语都翻译成目标中文,并显示在前端. 思路 我们会有三个具体的语言翻译结构体,或许以后还有更多,但现在分 ...
- php 设计模式之观察者模式(订阅者模式)
php 设计模式之观察者模式 实例 没用设计模式的代码,这样的代码要是把最上面那部分也要符合要求加进来,就要修改代码,不符合宁增不改的原则 介绍 观察者模式定义对象的一对多依赖,这样一来,当一个对象改 ...
- [JS设计模式]:观察者模式(即发布-订阅者模式)(4)
简介 观察者模式又叫发布---订阅模式,它定义了对象间的一种一对多的关系,让多个观察者对象同时监听某一个主题对象,当一个对象发生改变时,所有依赖于它的对象都将得到通知. 举一个现实生活中的例子,例如小 ...
- 数据结构和算法(Golang实现)(13)常见数据结构-可变长数组
可变长数组 因为数组大小是固定的,当数据元素特别多时,固定的数组无法储存这么多的值,所以可变长数组出现了,这也是一种数据结构.在Golang语言中,可变长数组被内置在语言里面:切片slice. sli ...
- 实践GoF的23种设计模式:观察者模式
摘要:当你需要监听某个状态的变更,且在状态变更时通知到监听者,用观察者模式吧. 本文分享自华为云社区<[Go实现]实践GoF的23种设计模式:观察者模式>,作者: 元闰子 . 简介 现在有 ...
- java设计模式之观察者模式
观察者模式 观察者模式(有时又被称为发布(publish )-订阅(Subscribe)模式.模型-视图(View)模式.源-收听者(Listener)模式或从属者模式)是软件设计模式的一种.在此种模 ...
随机推荐
- 启动Jenkins后无法访问,如何排错
做IT工作,使用各种工具的时候,遇到错误都是一堆英文,对于英语不好的人,看到报错可能就会心烦,我刚开始就是这种状态.后来,遇到问题,首先复制报错信息到百度上搜索,没有人请教的时候,你不能坐等问题自己解 ...
- NOIP模拟74
前言 我就想说一句,T3 给了一个什么牛马大样例!!!!!!!!,气\(^{TM}\)死我!!!!!!! 我的 \(\mathcal{O}(n)\) 算法始终过不掉大样例我 TM ,要不然我就直接上矩 ...
- 对于caffe程序中出现的Unknown database backend问题的报错怎么办?
在预处理器中添加USE_LMDB,因为caffe需要一种数据输入格式 这样,在db.cpp中#ifdef USE_LMDB就会变亮,显示使用的数据格式为LMDB
- oracle数据导入"HIST_GRAM_LIST_ITEM"问题处理
1.问题显示 处理对象类型 SCHEMA_EXPORT/TABLE/CONSTRAINT/REF_CONSTRAINT ORA-39083: 对象类型 REF_CONSTRAINT 创建失败, 出现错 ...
- 6岁!是时候重新认识下Serverless了
一.背景 Serverless 概念从2012年开始提出,真正推出相关云产品是2014年AWS推出Lambda.如果我们将 Serverless 比作一个婴儿,那么它已经6岁了. 虽然业界对Serve ...
- 配置Internal Load balancer中VM的外网访问
当在Azure中部署SQL VM时,处于安全考虑,不会配置VM的Public IP,会禁止外网的进出站访问,只允许从内部VNET,或者特定的内部IP访问.特别是当使用Azure Internal Lo ...
- 洛谷4035 JSOI2008球形空间产生器 (列柿子+高斯消元)
题目链接 qwq 首先看到这个题,感觉就应该从列方程入手. 我们设给定的点的坐标矩阵是\(x\),然后球心坐标\(a_1,a_2....a_n\) 根据欧几里得距离公式,对于一个\(n维空间\)的第\ ...
- 复杂对象List集合的排序
对于集合的排序,直接的有sort().间接的有借用compareTo.Comparable等,但是对于相对复杂的对象集合,还得自己实现方法来处理. 现在有这样一个思路: 第一步:从需要排序的对象集合中 ...
- STM32中操作寄存器GPIOB_CRL &= ~( 0x0F<< (4*0))与GPIOB_CRL &=~(0x0F)之间有什么区别吗?
没有区别,作用相同.只是这样写便于修改和沿用. 对于只用到PB0端口的程序~(0x0f << (4*0)) 和~0x0f没有区别.0x0f <<(4*N) 就是 向左 移动N个 ...
- 微信小程序的登录流程
一.背景 传统的web开发实现登陆功能,一般的做法是输入账号密码.或者输入手机号及短信验证码进行登录 服务端校验用户信息通过之后,下发一个代表登录态的 token 给客户端,以便进行后续的交互,每当t ...