设计模式: 行为型之中观察者模式(19)

2024-04-12 22:44

本文主要是介绍设计模式: 行为型之中观察者模式(19),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

观察者模式概述

  • 观察者模式(Observer Pattern)是一种行为设计模式
  • 它定义了对象之间的依赖关系,当一个对象(被称为主题或发布者)的状态改变时
  • 所有依赖于它的对象(被称为观察者)都会得到通知并自动更新

观察者模式应用

// 定义观察者接口
interface Observer {update(data: any): void; // 更新方法,当主题状态改变时,观察者通过这个方法获取更新
}// 定义主题接口
interface Subject {attach(observer: Observer): void; // 注册观察者detach(observer: Observer): void; // 移除观察者notify(data: any): void; // 通知所有观察者状态改变
}// 创建一个具体主题类实现
class ConcreteSubject implements Subject {private observers: Observer[] = []; // 存储观察者集合private state: any;getState(): any {return this.state;}setState(newState: any): void {this.state = newState;this.notify(newState);}attach(observer: Observer): void {this.observers.push(observer);}detach(observer: Observer): void {const index = this.observers.indexOf(observer);if (index !== -1) {this.observers.splice(index, 1);}}notify(data: any): void {this.observers.forEach((observer) => observer.update(data));}
}// 创建一个具体观察者类实现
class ConcreteObserver implements Observer {private name: string;constructor(name: string) {this.name = name;}update(data: any): void {console.log(`${this.name} received the update: ${data}`);}
}// 使用示例
function main() {const subject = new ConcreteSubject();const observer1 = new ConcreteObserver("Observer 1");const observer2 = new ConcreteObserver("Observer 2");subject.attach(observer1);subject.attach(observer2);subject.setState("New State");
}main();
  • 在这个例子中, Observer 接口定义了观察者所需要实现的 update 方法,当主题状态改变时,观察者通过这个方法获取更新信息
  • Subject 接口定义了主体类需要实现的方法,包括注册观察者(attach)、移除观察者(detach)和通知所有观察者(notify
  • ConcreteSubject类实现了 Subject 接口,其中存储了观察者列表,并在状态改变时通过 notify 方法通知所有观察者
  • ConcreteObserver 类实现了 Observer 接口,当接收到更新时,会打印出更新的信息
  • main 函数中,我们创建了一个具体主题对象和两个具体观察者对象,将观察者对象注册到主题对象,然后更改主题状态,触发观察者对象的 update 方法执行

观察者模式与发布订阅的区别和联系

  • 观察者模式(Observer Pattern)和发布订阅模式(Publish-Subscribe Pattern)在设计理念上具有一定的相似性,都涉及到对象间的一对多依赖关系和事件通知机制,但它们在具体实现和适用场景上有所区别
  • 观察者模式是经典的23种设计模式之一,属于行为型设计模式,它强调的是当对象状态改变时,能够自动通知其依赖的对象
  • 发布订阅模式虽然在某些文献中也被看作是观察者模式的一个扩展或变体,但它并不是23种经典设计模式中明确列出的模式
  • 发布订阅模式更倾向于在分布式系统和消息传递系统中应用,它通过引入消息中间件或者事件总线等机制进一步解耦了发布者和订阅者,使得它们可以异步处理消息,甚至在不同的进程中或服务器之间进行通信

1 )观察者模式(Observer Pattern)

  • 定义
    • 定义了一种一对多的依赖关系,当一个对象(Subject)的状态发生改变时
    • 所有依赖于它的对象(Observer)都会得到通知并自动更新
  • 特点
    • 直接依赖:观察者(Observer)直接订阅目标(Subject)的状态变化
    • 同步或异步:观察者模式既可以实现为同步也可以实现为异步,取决于具体实现
    • 弱耦合:Subject只知道有观察者接口的存在,而不需要了解具体的观察者实现
    • 应用场景:常应用于单个应用程序内部,如GUI编程中的事件处理、组件间通信等

2 )发布订阅模式(Publish-Subscribe Pattern)

  • 定义
    • 又称发布-订阅模式,引入了一个消息中心(Event Channel/Mediator)的概念,发布者(Publisher)发布事件到消息中心
    • 订阅者(Subscriber)从消息中心订阅感兴趣的事件,两者并不直接相互依赖
  • 特点
    • 间接依赖:发布者和订阅者之间通过一个独立的媒介(消息中心)交换消息。
    • 强烈异步:发布订阅模式通常采用异步的方式处理消息,更适合分布式环境和大规模系统的事件通信。
    • 更高的解耦程度:发布者和订阅者完全不了解对方的存在,它们通过事件名称进行匹配。
    • 应用场景:广泛应用于分布式系统、消息队列、跨进程/跨应用通信、微服务架构等。

3 )区别与联系


3.1 区别

  • 关系模型:观察者模式是直接对象间的互动,而发布订阅模式通过第三方(消息中心)中转。
  • 异步处理:观察者模式不一定异步,发布订阅模式通常是异步的。
  • 适用范围:观察者模式常见于单一应用内,发布订阅模式更适合分布式和跨系统的事件处理。

3.2 联系

  • 都是事件驱动:两者都基于事件通知机制,解决了对象间的通知和联动问题
  • 解耦思想:都旨在减少对象间的直接耦合,使得系统更灵活,更易于扩展和维护。

4 )总结

  • 观察者模式着重于对象级别的直接观察和通知
  • 而发布订阅模式则更加强调通过消息渠道在更大范围内的事件传播和订阅
  • 在实际应用中,观察者模式往往是发布订阅模式的一种实现方式,特别是在单体应用中
  • 而在分布式系统中,发布订阅模式往往更为普遍,因为它能够更好地支持松耦合和异步通信
  • 所以,观察者模式是23种设计模式中的一个正式成员,而发布订阅模式虽在理念上与之类似
  • 但在实践中体现出了更广泛的适用性和更强的解耦能力,它是观察者模式在特定场景下的自然延伸和发展

发布订阅的应用

发布订阅模式(Publish-Subscribe Pattern)在TypeScript中的实践应用通常涉及事件分发和处理中心,也就是一个事件总线或事件通道

以下是一个基本的TypeScript实现

// 定义事件接口
interface Event {type: string;data?: any;
}// 定义订阅者接口
interface Subscriber {subscribe(eventType: string, callback: (event: Event) => void): void;unsubscribe(eventType: string, callback: (event: Event) => void): void;
}// 实现一个简单的发布订阅类
class PubSub implements Subscriber {private eventCallbacks: Map<string, ((event: Event) => void)[]> = new Map();// 订阅事件subscribe(eventType: string, callback: (event: Event) => void): void {let callbacks = this.eventCallbacks.get(eventType);if (!callbacks) {callbacks = [];this.eventCallbacks.set(eventType, callbacks);}callbacks.push(callback);}// 取消订阅事件unsubscribe(eventType: string, callback: (event: Event) => void): void {const callbacks = this.eventCallbacks.get(eventType);if (callbacks) {const index = callbacks.indexOf(callback);if (index > -1) {callbacks.splice(index, 1);}}}// 发布事件publish(event: Event): void {const callbacks = this.eventCallbacks.get(event.type);if (callbacks) {callbacks.forEach(cb => cb(event));}}
}// 使用示例
class UserComponent {private pubsub: PubSub;constructor(pubsub: PubSub) {this.pubsub = pubsub;this.initListeners();}initListeners() {this.pubsub.subscribe('user:login', this.onUserLogin.bind(this));}onUserLogin(event: Event) {console.log('User logged in:', event.data);}triggerUserLogin(user: any) {this.pubsub.publish({ type: 'user:login', data: user });}
}// 初始化PubSub实例和UserComponent
const pubsub = new PubSub();
const userComponent = new UserComponent(pubsub);// 触发用户登录事件
userComponent.triggerUserLogin({ username: 'example' });
  • 在这个例子中:定义了 Event 接口描述事件的基本结构,包括事件类型和携带的数据
  • Subscriber 接口定义了订阅和取消订阅事件的方法
  • PubSub 类实现了 Subscriber 接口,维护了一个事件类型与回调函数数组的映射表,可以订阅、取消订阅事件以及发布事件
  • UserComponent 类作为一个使用者,通过 PubSub 类订阅特定事件,并在事件触发时执行相关操作。当用户登录时,通过 triggerUserLogin 方法发布事件
  • 这样,通过发布订阅模式,我们可以轻松地在不同的组件间解耦事件的触发和响应逻辑,使得整个系统更加灵活和可扩展

关于浏览器UI点击事件

  • UI上的按钮点击事件通常更接近于观察者模式

  • 在观察者模式中,一个对象(称为主题或可观察对象)维护一个依赖于它的对象列表(称为观察者),当主题的状态发生变化时,它会通知所有的观察者

  • 具体到UI上的按钮点击事件,按钮本身可以被看作是可观察对象,而点击事件的监听器或回调函数则是观察者

  • 当按钮被点击时,它的状态发生了变化(从未被点击到被点击),此时它会通知所有注册了点击事件的监听器或回调函数,这些监听器或回调函数随后会执行相应的操作

  • 虽然发布订阅模式与观察者模式在概念上有相似之处,但在典型的发布订阅模式中,消息是通过一个中央的消息代理(或称为发布者/订阅者管理器)进行传递的

  • 发布者将消息发布到消息代理,而订阅者则从消息代理中订阅它们感兴趣的消息。这种模式在分布式系统或大型应用中更为常见,因为它可以实现更高级别的解耦和灵活性。

  • 然而,在UI按钮点击事件的上下文中,通常没有这样一个中央的消息代理

  • 按钮直接与其监听器或回调函数进行交互,因此更符合观察者模式的直接交互特性

  • 总结来说,UI上的按钮点击事件通常被视为观察者模式的一个实例,尽管在某些情况下,也可以将其设计为实现发布订阅模式,但这通常不是最常见的做法

这篇关于设计模式: 行为型之中观察者模式(19)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/898442

相关文章

Java设计模式---迭代器模式(Iterator)解读

《Java设计模式---迭代器模式(Iterator)解读》:本文主要介绍Java设计模式---迭代器模式(Iterator),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录1、迭代器(Iterator)1.1、结构1.2、常用方法1.3、本质1、解耦集合与遍历逻辑2、统一

Java 线程安全与 volatile与单例模式问题及解决方案

《Java线程安全与volatile与单例模式问题及解决方案》文章主要讲解线程安全问题的五个成因(调度随机、变量修改、非原子操作、内存可见性、指令重排序)及解决方案,强调使用volatile关键字... 目录什么是线程安全线程安全问题的产生与解决方案线程的调度是随机的多个线程对同一个变量进行修改线程的修改操

Redis Cluster模式配置

《RedisCluster模式配置》:本文主要介绍RedisCluster模式配置,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录分片 一、分片的本质与核心价值二、分片实现方案对比 ‌三、分片算法详解1. ‌范围分片(顺序分片)‌2. ‌哈希分片3. ‌虚

RabbitMQ工作模式中的RPC通信模式详解

《RabbitMQ工作模式中的RPC通信模式详解》在RabbitMQ中,RPC模式通过消息队列实现远程调用功能,这篇文章给大家介绍RabbitMQ工作模式之RPC通信模式,感兴趣的朋友一起看看吧... 目录RPC通信模式概述工作流程代码案例引入依赖常量类编写客户端代码编写服务端代码RPC通信模式概述在R

SQL Server身份验证模式步骤和示例代码

《SQLServer身份验证模式步骤和示例代码》SQLServer是一个广泛使用的关系数据库管理系统,通常使用两种身份验证模式:Windows身份验证和SQLServer身份验证,本文将详细介绍身份... 目录身份验证方式的概念更改身份验证方式的步骤方法一:使用SQL Server Management S

Spring Boot 事务详解(事务传播行为、事务属性)

《SpringBoot事务详解(事务传播行为、事务属性)》SpringBoot提供了强大的事务管理功能,通过@Transactional注解可以方便地配置事务的传播行为和属性,本文将详细介绍Spr... 目录Spring Boot 事务详解引言声明式事务管理示例编程式事务管理示例事务传播行为1. REQUI

Redis高可用-主从复制、哨兵模式与集群模式详解

《Redis高可用-主从复制、哨兵模式与集群模式详解》:本文主要介绍Redis高可用-主从复制、哨兵模式与集群模式的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝... 目录Redis高可用-主从复制、哨兵模式与集群模式概要一、主从复制(Master-Slave Repli

一文带你搞懂Redis Stream的6种消息处理模式

《一文带你搞懂RedisStream的6种消息处理模式》Redis5.0版本引入的Stream数据类型,为Redis生态带来了强大而灵活的消息队列功能,本文将为大家详细介绍RedisStream的6... 目录1. 简单消费模式(Simple Consumption)基本概念核心命令实现示例使用场景优缺点2

Nginx location匹配模式与规则详解

《Nginxlocation匹配模式与规则详解》:本文主要介绍Nginxlocation匹配模式与规则,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、环境二、匹配模式1. 精准模式2. 前缀模式(不继续匹配正则)3. 前缀模式(继续匹配正则)4. 正则模式(大

Linux系统配置NAT网络模式的详细步骤(附图文)

《Linux系统配置NAT网络模式的详细步骤(附图文)》本文详细指导如何在VMware环境下配置NAT网络模式,包括设置主机和虚拟机的IP地址、网关,以及针对Linux和Windows系统的具体步骤,... 目录一、配置NAT网络模式二、设置虚拟机交换机网关2.1 打开虚拟机2.2 管理员授权2.3 设置子