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

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...

相关推荐
潘多编程25 分钟前
Spring Boot微服务架构设计与实战
spring boot·后端·微服务
2402_8575893630 分钟前
新闻推荐系统:Spring Boot框架详解
java·spring boot·后端
2401_8576226632 分钟前
新闻推荐系统:Spring Boot的可扩展性
java·spring boot·后端
Amagi.2 小时前
Spring中Bean的作用域
java·后端·spring
2402_857589362 小时前
Spring Boot新闻推荐系统设计与实现
java·spring boot·后端
J老熊3 小时前
Spring Cloud Netflix Eureka 注册中心讲解和案例示范
java·后端·spring·spring cloud·面试·eureka·系统架构
Benaso3 小时前
Rust 快速入门(一)
开发语言·后端·rust
sco52823 小时前
SpringBoot 集成 Ehcache 实现本地缓存
java·spring boot·后端
原机小子3 小时前
在线教育的未来:SpringBoot技术实现
java·spring boot·后端
吾日三省吾码3 小时前
详解JVM类加载机制
后端