设计模式: 行为型之中观察者模式(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

相关文章

详解Spring Boot接收参数的19种方式

《详解SpringBoot接收参数的19种方式》SpringBoot提供了多种注解来接收不同类型的参数,本文给大家介绍SpringBoot接收参数的19种方式,感兴趣的朋友跟随小编一起看看吧... 目录SpringBoot接受参数相关@PathVariable注解@RequestHeader注解@Reque

在JS中的设计模式的单例模式、策略模式、代理模式、原型模式浅讲

1. 单例模式(Singleton Pattern) 确保一个类只有一个实例,并提供一个全局访问点。 示例代码: class Singleton {constructor() {if (Singleton.instance) {return Singleton.instance;}Singleton.instance = this;this.data = [];}addData(value)

模版方法模式template method

学习笔记,原文链接 https://refactoringguru.cn/design-patterns/template-method 超类中定义了一个算法的框架, 允许子类在不修改结构的情况下重写算法的特定步骤。 上层接口有默认实现的方法和子类需要自己实现的方法

【iOS】MVC模式

MVC模式 MVC模式MVC模式demo MVC模式 MVC模式全称为model(模型)view(视图)controller(控制器),他分为三个不同的层分别负责不同的职责。 View:该层用于存放视图,该层中我们可以对页面及控件进行布局。Model:模型一般都拥有很好的可复用性,在该层中,我们可以统一管理一些数据。Controlller:该层充当一个CPU的功能,即该应用程序

迭代器模式iterator

学习笔记,原文链接 https://refactoringguru.cn/design-patterns/iterator 不暴露集合底层表现形式 (列表、 栈和树等) 的情况下遍历集合中所有的元素

《x86汇编语言:从实模式到保护模式》视频来了

《x86汇编语言:从实模式到保护模式》视频来了 很多朋友留言,说我的专栏《x86汇编语言:从实模式到保护模式》写得很详细,还有的朋友希望我能写得更细,最好是覆盖全书的所有章节。 毕竟我不是作者,只有作者的解读才是最权威的。 当初我学习这本书的时候,只能靠自己摸索,网上搜不到什么好资源。 如果你正在学这本书或者汇编语言,那你有福气了。 本书作者李忠老师,以此书为蓝本,录制了全套视频。 试

利用命令模式构建高效的手游后端架构

在现代手游开发中,后端架构的设计对于支持高并发、快速迭代和复杂游戏逻辑至关重要。命令模式作为一种行为设计模式,可以有效地解耦请求的发起者与接收者,提升系统的可维护性和扩展性。本文将深入探讨如何利用命令模式构建一个强大且灵活的手游后端架构。 1. 命令模式的概念与优势 命令模式通过将请求封装为对象,使得请求的发起者和接收者之间的耦合度降低。这种模式的主要优势包括: 解耦请求发起者与处理者

springboot实战学习(1)(开发模式与环境)

目录 一、实战学习的引言 (1)前后端的大致学习模块 (2)后端 (3)前端 二、开发模式 一、实战学习的引言 (1)前后端的大致学习模块 (2)后端 Validation:做参数校验Mybatis:做数据库的操作Redis:做缓存Junit:单元测试项目部署:springboot项目部署相关的知识 (3)前端 Vite:Vue项目的脚手架Router:路由Pina:状态管理Eleme

状态模式state

学习笔记,原文链接 https://refactoringguru.cn/design-patterns/state 在一个对象的内部状态变化时改变其行为, 使其看上去就像改变了自身所属的类一样。 在状态模式中,player.getState()获取的是player的当前状态,通常是一个实现了状态接口的对象。 onPlay()是状态模式中定义的一个方法,不同状态下(例如“正在播放”、“暂停

软件架构模式:5 分钟阅读

原文: https://orkhanscience.medium.com/software-architecture-patterns-5-mins-read-e9e3c8eb47d2 软件架构模式:5 分钟阅读 当有人潜入软件工程世界时,有一天他需要学习软件架构模式的基础知识。当我刚接触编码时,我不知道从哪里获得简要介绍现有架构模式的资源,这样它就不会太详细和混乱,而是非常抽象和易