观察者模式是一种行为型设计模式。这种模式允许一个实例(可以称为目标对象)发布各种事件(event)给其他实例(观察者)。这些观察者会对目标对象进行订阅,这样每当目标对象发生变化时,观察者就会收到事件(event)通知。

来看个例子:在电商网站经常会有各种商品脱销,假如有顾客已经在关注这些商品,这些商品的脱销就会对他们产生不好的体验。如果顾客还想买这些商品,那么通常有如下解决方案:

  1. 顾客以一定的频率检查这些商品是否在售
  2. 电商平台将所有的上架的商品信息定期推送给用户
  3. 顾客只订阅他所关注的特定商品的信息,当这些商品再次上架时他们会收到通知;多个顾客可以订阅同一个商品的信息

选项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 - 观察者模式的更多相关文章

  1. 乐在其中设计模式(C#) - 观察者模式(Observer Pattern)

    原文:乐在其中设计模式(C#) - 观察者模式(Observer Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 观察者模式(Observer Pattern) 作者:weba ...

  2. 设计模式之观察者模式(Observable与Observer)

    设计模式之观察者模式(Observable与Observer) 好久没有写博客啦,之前看完了<设计模式之禅>也没有总结一下,现在回忆一下设计模式之观察者模式. 1.什么是观察者模式 简单情 ...

  3. 8.5 GOF设计模式四: 观察者模式Observer

    GOF设计模式四: 观察者模式Observer  现实中遇到的问题  当有许多不同的客户都对同一数据源感兴趣,对相同的数据有不同的处理方式,该如 何解决?5.1 定义: 观察者模式  观察者模式 ...

  4. Golang设计模式—简单工厂模式(Simple Factory Pattern)

    Golang设计模式--简单工厂模式 背景 假设我们在做一款小型翻译软件,软件可以将德语.英语.日语都翻译成目标中文,并显示在前端. 思路 我们会有三个具体的语言翻译结构体,或许以后还有更多,但现在分 ...

  5. php 设计模式之观察者模式(订阅者模式)

    php 设计模式之观察者模式 实例 没用设计模式的代码,这样的代码要是把最上面那部分也要符合要求加进来,就要修改代码,不符合宁增不改的原则 介绍 观察者模式定义对象的一对多依赖,这样一来,当一个对象改 ...

  6. [JS设计模式]:观察者模式(即发布-订阅者模式)(4)

    简介 观察者模式又叫发布---订阅模式,它定义了对象间的一种一对多的关系,让多个观察者对象同时监听某一个主题对象,当一个对象发生改变时,所有依赖于它的对象都将得到通知. 举一个现实生活中的例子,例如小 ...

  7. 数据结构和算法(Golang实现)(13)常见数据结构-可变长数组

    可变长数组 因为数组大小是固定的,当数据元素特别多时,固定的数组无法储存这么多的值,所以可变长数组出现了,这也是一种数据结构.在Golang语言中,可变长数组被内置在语言里面:切片slice. sli ...

  8. 实践GoF的23种设计模式:观察者模式

    摘要:当你需要监听某个状态的变更,且在状态变更时通知到监听者,用观察者模式吧. 本文分享自华为云社区<[Go实现]实践GoF的23种设计模式:观察者模式>,作者: 元闰子 . 简介 现在有 ...

  9. java设计模式之观察者模式

    观察者模式 观察者模式(有时又被称为发布(publish )-订阅(Subscribe)模式.模型-视图(View)模式.源-收听者(Listener)模式或从属者模式)是软件设计模式的一种.在此种模 ...

随机推荐

  1. Java基础系列(11)- 变量、常量、作用域以及变量的命名规范

    变量 变量是什么:就是可以变化的量 Java是一种强类型语言,每个变量都必须声明其类型 Java变量是程序中最基本的存储单元,其要素包括变量名,变量类型和作用域 type varName [=valu ...

  2. Nginx系列(4)- Nginx安装 | Windows

    下载 访问官网,选择稳定版对应的Windows系列 安装解压即可 启动nginx 有很多种方法启动nginx 直接双击nginx.exe,双击后一个黑色的弹窗一闪而过 打开cmd命令窗口,切换到ngi ...

  3. ELK实战部署

    环境 : 一台 centos 6.7 IP地址: 192.168.88.250 软件版本 : ElasticSearch 2.1.0    Logstash 2.1.1  Kibana 4.3.1   ...

  4. jqGride的基本使用

    1. 定义:jqGrid是一个在jQuery基础上封装一个表格控件,以ajax的方式和服务器端通信. 2. 使用方式: 2.1 项目中引入jqGride的文件: 2.2 搭建开发页面:  2.3 构建 ...

  5. nginx rewrite重写规则集合

    本文根据网络搜索整理,不是原创 一.正则表达式匹配,其中: ~ 为区分大小写匹配 ~* 为不区分大小写匹配 !~和!~* 分别为区分大小写不匹配及不区分大小写不匹配 . 匹配除换行符以外的任意字符 \ ...

  6. NOI.AC#2144-子串【SAM,倍增】

    正题 题目链接:http://noi.ac/problem/2144 题目大意 给出一个字符串\(s\)和一个序列\(a\).将字符串\(s\)的所有本质不同子串降序排序后,求有多少个区间\([l,r ...

  7. Remote Sensing Images Semantic Segmentation with General Remote Sensing Vision Model via a Self-Supervised Contrastive Learning Method

    论文阅读: Remote Sensing Images Semantic Segmentation with General Remote Sensing Vision Model via a Sel ...

  8. 我惊了!CompletableFuture居然有性能问题!

    你好呀,我是歪歪. 国庆的时候闲来无事,就随手写了一点之前说的比赛的代码,目标就是保住前 100 混个大赛的文化衫就行了. 现在还混在前 50 的队伍里面,稳的一比. 其实我觉得大家做柔性负载均衡那题 ...

  9. 理解ASP.NET Core - 选项(Options)

    注:本文隶属于<理解ASP.NET Core>系列文章,请查看置顶博客或点击此处查看全文目录 Options绑定 上期我们已经聊过了配置(IConfiguration),今天我们来聊一聊O ...

  10. NOIP 模拟 七十七

    100+60+95+30; T4 一个变量打错挂了40.. T1 最大或 考虑从高到低枚举的二进制位,然后和的对应二进制位进行比较.如果两 者相同,那么不论怎么选择,,答案在这个位置上的值一定和在这个 ...