一文搞懂设计模式之观察者模式

hello,大家好,我是晴天,最近北京的流感病毒真不是开玩笑的,大家注意保重身体啊。本周我们继续学习设计模式系列之观察者模式。

什么是观察者模式

观察者模式是一种行为型设计模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听并被通知某一被观察对象的状态变化。当被观察对象的状态发生改变时,所有依赖于它的观察者都会收到通知,并自动更新。

这种模式的主要目标是实现对象之间的解耦,使得被观察对象和观察者对象可以独立地进行扩展和变化,而不会相互影响。观察者模式提供了一种简单而有效的机制,用于在对象之间建立一种发布-订阅机制,实现了一种松耦合的交互方式。

主要角色包括:

  1. 被观察者: 被观察的对象,它维护了一个观察者列表,提供了方法用于添加、删除和通知观察者。当自身状态发生变化时,会通知所有注册的观察者。

  2. 观察者: 观察者对象,它定义了在被观察者状态发生变化时应该执行的更新操作。每个观察者都必须实现观察者接口,该接口通常包含一个 update 方法,用于接收通知。

为什么需要观察者模式

观察者模式的核心思想是将被观察者和观察者解耦,使得它们之间的关系更为灵活。可以很方便地增加观察者和删除观察者,也可以很方便地让一个观察者订阅多个被观察者。


观察者模式跟发布订阅模式很相似,算是发布订阅模式的一种特殊情况吧,为了便于理解,下文就使用发布者和订阅者来表述被观察者和观察者。

实际场景

一个实际生活中使用观察者模式的例子------是天气预报系统。在这个系统中,气象站充当发布者(Publisher),而各个天气预报应用或网站充当订阅者(Subscriber)。

具体情景如下:

  1. 发布者(气象站): 气象站负责采集实时的气象数据,包括温度、湿度、风速等信息。气象站维护一个观察者列表,该列表中包含注册的各个天气预报应用或网站。

  2. 订阅者(天气预报应用或网站): 每个天气预报应用或网站都是观察者,它们希望及时获取气象站发布的最新气象数据,以更新用户显示的天气信息。

  3. 通知机制: 当气象站的气象数据发生变化时,它会遍历订阅者列表,逐个通知注册的天气预报应用或网站。每个订阅者在接收到通知后,会执行相应的更新操作,例如更新显示的天气信息。

这个例子中,观察者模式实现了气象站与天气预报应用或网站的解耦。气象站无需知道具体有哪些订阅者,而订阅者也无需了解气象站的内部实现细节。这种松耦合的设计使得系统更加灵活,可以方便地新增或删除天气预报应用或网站,而不影响其他部分的代码。

观察者模式在这种情景下非常适用,因为气象站的数据变化频繁,而各个订阅者希望能够及时获取最新的信息进行更新。

代码实战

scss 复制代码
package main

import "fmt"

// 抽象层
// 发布者接口
type Publisher interface {
	Follow(s Subscriber)
	UnFollow(s Subscriber)
	Notify()
}

// 订阅者接口
type Subscriber interface {
	Update() // 接到通知,执行自己的方法
	Name() string
}

// 实现层
// 具体发布者
type ConcretePublisher struct {
	subscribers []Subscriber
}

// 观察者订阅
func (c *ConcretePublisher) Follow(s Subscriber) {
	c.subscribers = append(c.subscribers, s)
}

// 观察者取消订阅
func (c *ConcretePublisher) UnFollow(s Subscriber) {
	c.subscribers = remove(c.subscribers, s)
}

// 通知所有观察只
func (c *ConcretePublisher) Notify() {
	for _, s := range c.subscribers {
		s.Update()
	}
}

func remove(s []Subscriber, s1 Subscriber) []Subscriber {
	for i, concreteSubscriber1 := range s {
		if concreteSubscriber1.Name() == s1.Name() {
			s = append(s[:i], s[i+1:]...)
		}
	}
	return s
}

// 具体订阅者
type ConcreteSubscriber struct {
	name string
}

func (c *ConcreteSubscriber) Update() {
	fmt.Println(c.name + "收到订阅通知")
}

func (c *ConcreteSubscriber) Name() string {
	return c.name
}

// 业务逻辑层
func main() {
	var publisher Publisher
	publisher = &ConcretePublisher{}
	var subscriber1 Subscriber
	var subscriber2 Subscriber
	subscriber1 = &ConcreteSubscriber{"墨迹天气"}
	subscriber2 = &ConcreteSubscriber{"今日头条"}
	publisher.Follow(subscriber1)
	publisher.Follow(subscriber2)
	publisher.Notify()
}

// 输出结果:
墨迹天气收到订阅通知
今日头条收到订阅通知

代码解释:

上述代码定义了发布者接口和订阅者接口,具体的发布者需要实现 Follow 方法来注册订阅者、UnFollow 方法来移除订阅者、Notify 来通知订阅者。具体的订阅者需要实现 Update 方法来触发接收到通知后应该做的动作。

总结

本位介绍了什么是观察者模式,实际上就是定义了一种一对多的通知模式;介绍了为什么需要观察者模式,能够实现观察者和被观察者之间的解耦随意进行订阅。

写在最后

感谢大家的阅读,晴天将继续努力,分享更多有趣且实用的主题,如有错误和纰漏,欢迎留言给予指正。 更多文章敬请关注作者个人公众号 晴天码字。 我们下期不见不散,to be continued...

相关推荐
咖啡啡不加糖21 分钟前
雪花算法:分布式ID生成的优雅解决方案
java·分布式·后端
姑苏洛言1 小时前
基于微信公众号小程序的课表管理平台设计与实现
前端·后端
烛阴1 小时前
比UUID更快更小更强大!NanoID唯一ID生成神器全解析
前端·javascript·后端
why1511 小时前
字节golang后端二面
开发语言·后端·golang
还是鼠鼠1 小时前
单元测试-断言&常见注解
java·开发语言·后端·单元测试·maven
cainiao0806051 小时前
Spring Boot 4.0实战:构建高并发电商系统
java·spring boot·后端
Chandler242 小时前
Go 即时通讯系统:日志模块重构,并从main函数开始
后端·重构·golang·gin
酷爱码3 小时前
Spring Boot Starter 自动装配原理全解析:从概念到实践
java·开发语言·spring boot·后端·spring
小奏技术4 小时前
虚拟线程 vs. 传统线程池:Spring Boot 3.x I/O密集型任务性能对比
后端
JavaEdge.4 小时前
Spring 5 响应式编程:构建高性能全栈应用的关键
java·后端·spring