观察者模式是一种行为型设计模式。这种模式允许一个实例(可以称为目标对象)发布各种事件(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. Jmeter扩展组件开发(1) - 创建maven工程

    前言 没有安装IDEA的伙伴先安装.url:https://www.cnblogs.com/gltou/p/14956060.html 扩展开发实现的两种方式 继承AbstracJavaSampler ...

  2. Groovy系列(2)- Groovy与Java的不同之处

    Groovy与Java的不同之处 默认 imports 所有这些包和类都是默认导入的,不必使用显式import语句来使用它们 java.io.* java.lang.* java.math.BigDe ...

  3. MSSQL数据库安全实验

    管理SQL Server认证模式 (1)确认 SQL Server 验证 ①在桌面上单击"开始",选择"程序"→"Microsoft SQL Serv ...

  4. 微服务+异步工作流+ Serverless,Netflix 决定弃用稳定运行 7 年的旧平台

    作者 | Frank San Miguel 策划 | 田晓旭 2021 年,Netflix 会将大部分的工作负载从 Reloaded 转移到 Cosmos 平台.Cosmos 是一个计算平台,它将微服 ...

  5. logstash输出到rabbitmq

    场景 将应用日志文件发送到rabbitmq. filebeat 不支持rabbitmq作为输出.因此,需要先将文件由filebeat发送到logstash ,再由logstash 输出到rabbitm ...

  6. 2021MySQL 8.0.26安装教程,目前最新版(详细全面)

    MySQL 8 要比 MySQL 5.7 快 2 倍,还带来了大量的改进和更快的性能!所以为什么不用MySQL8呢!下面是MySQL 8.0.26的安装教程. 安装网址: https://dev.my ...

  7. Java(1)开发环境配置及第一个程序Hello World

    作者:季沐测试笔记 原文地址:https://www.cnblogs.com/testero/p/15201468.html 博客主页:https://www.cnblogs.com/testero ...

  8. Flask聚合函数(基本聚合函数、分组聚合函数、去重聚合函数))

    Flask聚合函数 1.基本聚合函数(sun/count/max/min/avg) 使用聚合函数先导入:from sqlalchemy import func 使用方法: sun():func.sum ...

  9. python中常用的导包的方法和常用的库

    python中常用的导包的方法               导入包和包名的方法:1.import package.module 2.from package.module import  * 例一: ...

  10. JVM详解(六)——对象的实例化、内存布局与访问定位

    一.对象的实例化 1.创建对象的方式 2.创建对象的步骤 脑图:https://www.processon.com/view/link/61701a927d9c087040525226 3.对象属性赋 ...