当前位置: 首页 > news >正文

TypeScript 设计模式之【观察者模式】

文章目录

  • 观察者模式:构建灵活响应的事件通知系统
  • 观察者模式的奥秘
    • 观察者模式有什么利与弊?
    • 如何使用观察者模式来优化你的系统
    • 代码实现案例
    • 观察者模式的主要优点
    • 观察者模式的主要缺点
    • 观察者模式的适用场景
    • 总结

在这里插入图片描述

观察者模式:构建灵活响应的事件通知系统

每当有订阅热点事件发生时,你都会立即收到通知。这个过程中,你就像一个"观察者",而热点事件应用则是"被观察者"。这种实时更新的机制,正是观察者模式的生动体现。

软件开发中,我们经常需要处理对象之间的一对多依赖关系,一个对象状态改变时,所有依赖于它的对象都能得到通知并自动更新。观察者模式类似一个智能的通知系统,能够在保持对象之间松耦合的同时,灵活处理事件!

观察者模式的奥秘

观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

观察者模式有什么利与弊?

观察者模式的优点是它支持广播通信,增加了灵活性和可扩展性。它遵循开闭原则,使得我们可以在不修改现有代码的情况下添加新的观察者。缺点是如果处理不当,会引起性能问题和循环依赖。

如何使用观察者模式来优化你的系统

观察者模式涉及角色

  • 主题(Subject): 定义添加、删除和通知观察者的接口
  • 具体主题(ConcreteSubject): 实现主题接口,维护观察者列表,发生变化时通知观察者
  • 观察者(Observer): 定义一个更新接口,使在主题状态变化时得到通知
  • 具体观察者(ConcreteObserver): 实现观察者更新接口,以便在得到通知时进行自我更新

观察者模式步骤

  1. 创建一个主题接口,定义添加、删除和通知观察者的方法
  2. 创建一个观察者接口,定义更新方法
  3. 实现具体主题类,维护观察者列表,实现通知逻辑
  4. 实现具体观察者类,定义在收到通知时的具体行为
  5. 在主题状态改变时,通知所有注册的观察者

选择合适的观察者模式,你就能轻松地实现对象之间的解耦,让系统变得更加灵活和可扩展!

代码实现案例

// 观察者接口
interface Observer {update(message: string): void;
}// 主题接口
interface Subject {// 附加attach(observer: Observer): void;// 脱离detach(observer: Observer): void;// 通知notify(message: string): void;
}// 具体主题:新闻发布者
class NewsPublisher implements Subject {private observers: Observer[] = [];attach(observer: Observer): void {const isExist = this.observers.includes(observer);if (isExist) {return console.log("观察者已经存在,无需重复添加");}this.observers.push(observer);console.log("观察者已添加");}detach(observer: Observer): void {const observerIndex = this.observers.indexOf(observer);if (observerIndex === -1) {return console.log("未找到要删除的观察者");}this.observers.splice(observerIndex, 1);console.log("观察者已被移除");}notify(message: string): void {console.log("通知所有观察者");for (const observer of this.observers) {observer.update(message);}}publishNews(news: string): void {console.log(`发布新闻: ${news}`);this.notify(news);}
}// 具体观察者:新闻订阅者
class NewsSubscriber implements Observer {private name: string;constructor(name: string) {this.name = name;}update(message: string): void {console.log(`${this.name} 收到新闻: ${message}`);}
}
// 客户端代码
const publisher = new NewsPublisher();const subscriber1 = new NewsSubscriber("张三");
const subscriber2 = new NewsSubscriber("李四");
const subscriber3 = new NewsSubscriber("王五");publisher.attach(subscriber1);
publisher.attach(subscriber2);
publisher.attach(subscriber3);publisher.publishNews("中国成功发射神舟十八号载人飞船!");publisher.detach(subscriber2); // 李四通知被移除publisher.publishNews("2023年高考开始了!");// 输出
// 观察者已添加
// 观察者已添加
// 观察者已添加
// 发布新闻: 中国成功发射神舟十八号载人飞船!
// 通知所有观察者
// 张三 收到新闻: 中国成功发射神舟十八号载人飞船!
// 李四 收到新闻: 中国成功发射神舟十八号载人飞船!
// 王五 收到新闻: 中国成功发射神舟十八号载人飞船!
// 观察者已被移除
// 发布新闻: 2023年高考开始了!
// 通知所有观察者
// 张三 收到新闻: 2023年高考开始了!
// 王五 收到新闻: 2023年高考开始了!

在这里插入图片描述

观察者模式的主要优点

  1. 松耦合: 主题和观察者之间是松散耦合的,它们依然可以独立地改变
  2. 支持广播通信: 主题无需知道观察者的具体类,只需通知所有观察者
  3. 灵活性和可扩展性: 可以动态地增加或删除观察者,无需修改主题
  4. 符合开闭原则: 无需修改主题就可以引入新的观察者类

观察者模式的主要缺点

  1. 引起性能问题: 如果观察者数量太多,通知所有观察者会花费较多时间
  2. 导致循环依赖: 观察者和主题之间可能出现循环依赖
  3. 通知次序不可控: 不保证通知顺序,可能导致不一致的状态
  4. 意外的更新: 如果观察者之间有依赖关系,可能导致意外的更新

观察者模式的适用场景

  1. 当一个抽象模型有两个方面,其中一个方面依赖于另一个方面时
  2. 当对一个对象的改变需要同时改变其他对象,而不知道具体有多少对象待改变时
  3. 当一个对象必须通知其他对象,而它又不能假定其他对象是谁时
  4. 需要在系统中创建一个触发链时

总结

观察者模式是一种行为型设计模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。当主题对象的状态发生变化时,所有依赖于它的观察者都会得到通知并自动更新。观察者模式通过解耦主题和观察者,提高了系统的灵活性和可扩展性。合理使用观察者模式,可以让你的代码更加模块化,更易于维护和扩展。

喜欢的话就点个赞 ❤️,关注一下吧,有问题也欢迎讨论指教。感谢大家!!!

下期预告: TypeScript 设计模式之【状态模式】

相关文章:

  • 照片压缩方法分享,掌握这些小技巧轻松压缩
  • Python中的数据处理与分析:从基础到高级
  • django开发流程1
  • 图像生成大模型 Imagen:AI创作新纪元
  • 9_23_QT窗口
  • 【C/C++】【基础数论】33、算数基本定理
  • 选择租用徐州存储服务器有什么作用?
  • 数据库系列(1)常见的四种非关系型数据库(NoSQL)
  • 前端Vue学习笔记02
  • go的结构体、方法、接口
  • 【1分钟学会】实用的Git工作流程
  • 初学51单片机之I2C总线与E2PROM
  • 追随 HarmonyOS NEXT,Solon v3.0 将在10月8日发布
  • 基于饥饿游戏搜索优化随机森林的数据回归预测 MATLAB 程序 HGS-RF
  • Could not find com.mapbox.mapboxsdk:mapbox-android-accounts:0.7.0.解决
  • hexo+github搭建个人博客
  • @jsonView过滤属性
  • css属性的继承、初识值、计算值、当前值、应用值
  • Java 11 发布计划来了,已确定 3个 新特性!!
  • Java多线程(4):使用线程池执行定时任务
  • LintCode 31. partitionArray 数组划分
  • Mysql优化
  • PaddlePaddle-GitHub的正确打开姿势
  • Spark RDD学习: aggregate函数
  • Spark VS Hadoop:两大大数据分析系统深度解读
  • TCP拥塞控制
  • zookeeper系列(七)实战分布式命名服务
  • 你真的知道 == 和 equals 的区别吗?
  • 手写双向链表LinkedList的几个常用功能
  • 通过几道题目学习二叉搜索树
  • 项目管理碎碎念系列之一:干系人管理
  • 06-01 点餐小程序前台界面搭建
  • AI又要和人类“对打”,Deepmind宣布《星战Ⅱ》即将开始 ...
  • Salesforce和SAP Netweaver里数据库表的元数据设计
  • 进程与线程(三)——进程/线程间通信
  • ​3ds Max插件CG MAGIC图形板块为您提升线条效率!
  • ​flutter 代码混淆
  • ​LeetCode解法汇总2696. 删除子串后的字符串最小长度
  • ​LeetCode解法汇总518. 零钱兑换 II
  • #C++ 智能指针 std::unique_ptr 、std::shared_ptr 和 std::weak_ptr
  • #Z2294. 打印树的直径
  • #我与Java虚拟机的故事#连载16:打开Java世界大门的钥匙
  • ()、[]、{}、(())、[[]]等各种括号的使用
  • (145)光线追踪距离场柔和阴影
  • (vue)el-cascader级联选择器按勾选的顺序传值,摆脱层级约束
  • (二)丶RabbitMQ的六大核心
  • (附源码)springboot建达集团公司平台 毕业设计 141538
  • (附源码)计算机毕业设计SSM基于java的云顶博客系统
  • (汇总)os模块以及shutil模块对文件的操作
  • (转)fock函数详解
  • (转)memcache、redis缓存
  • .net 7和core版 SignalR
  • .NET Core WebAPI中封装Swagger配置
  • .NET LINQ 通常分 Syntax Query 和Syntax Method
  • .NET微信公众号开发-2.0创建自定义菜单