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

观察者模式的实现

引言:观察者模式——程序中的“通信兵”

在现代战争中,通信是胜利的关键。信息力以网络、数据、算法、算力等为底层支撑,在现代战争中不断推动感知、决策、指控等各环节产生量变与质变。在软件架构中,观察者模式扮演着类似的角色,它是确保信息在系统中高效、准确地流动的“通信兵”。
在这里插入图片描述

观察者模式确保了在软件系统中,当一个对象的状态发生变化时,所有依赖于这个状态的对象都能够及时得到通知。这种模式通过定义对象间的一对多依赖关系,使得一个对象的改变能够自动传播到其他对象。

观察者模式的概念

观察者模式是一种行为设计模式,它定义了对象间的一种一对多的依赖关系,使得当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。这种模式非常适合于实现分布式事件处理系统,如用户界面元素的响应、股票价格更新通知等。

为什么选择观察者模式?

  1. 降低耦合度:观察者模式通过定义对象间的依赖关系,降低了组件之间的耦合度,使得系统更加模块化。

  2. 提高系统的可扩展性:当需要增加新的观察者或被观察对象时,不需要修改现有的代码,只需遵循观察者模式的规则即可。

  3. 增强系统的灵活性:观察者模式允许对象在运行时动态地注册或注销观察者,使得系统能够灵活地响应变化。

本文的目的

在本文中,我们将深入探讨观察者模式的工作原理、实现方式以及如何在实际项目中应用它。

走近现实,聊聊军事下的“观察者模式”

观察者模式的角色构成

朱日和军演是中国每年举行的一次大规模军事演习,涉及多个部队和指挥中心。在这个例子中,我们可以将观察者模式应用到演习的指挥系统中。

主题(Subject):朱日和军演总指挥中心

  • 总指挥中心负责制定演习计划,并维护一个观察者列表。

观察者(Observer):参演部队的指挥官或通信兵

  • 参演部队的指挥官或通信兵希望在演习计划发生变化时能够收到通知。

具体主题(ConcreteSubject):具体的朱日和军演总指挥中心

  • 具体的总指挥中心会在演习计划发生变化时通知所有观察者。

具体观察者(ConcreteObserver):具体的参演部队

  • 具体的参演部队会在收到通知后,根据新的演习计划调整行动。

观察者模式的工作流程

  1. 注册: 各个参演部队向总指挥中心注册,表示自己希望收到演习计划的更新。

  2. 计划变更: 当总指挥中心制定了新的演习计划或现有计划发生变化时,计划变更被触发。

  3. 通知: 总指挥中心通知所有注册的参演部队,告知他们演习计划已经更新。

  4. 更新: 各个参演部队接收到通知后,根据新的演习计划调整自己的行动。

观察者模式的实现流程

下面,我将以朱日和军演的例子,将演习计划的变更通知到每一个参演部队,确保所有部队能够及时调整行动,协同作战。
在这里插入图片描述

第一步,新建一个主题接口,主要定义了注册、移除和通知观察者的方法。这是所有具体指挥中心必须实现的接口。

// 主题接口:军事指挥中心
public interface CommandCenter {// 注册观察者void registerObserver(Observer observer);// 移除观察者void removeObserver(Observer observer);// 通知所有注册的观察void notifyObservers(String exercisePlan);
}

第二步,新建一个观察者接口,其定义了一个更新方法,用于接收主题的通知。这是所有具体观察者必须实现的接口。

// 观察者:接收主题的通知
public interface Observer {void update(String message);
}

第三步,创建具体主题类,实现了 CommandCenter 接口,负责管理观察者列表,并在演习计划改变时通知所有观察者。

// 具体主题类:朱日和指挥中心
public class ZhuRiHeCommandCenter implements CommandCenter {private List<Observer> observers = new ArrayList<>();@Overridepublic void registerObserver(Observer observer) {observers.add(observer);}@Overridepublic void removeObserver(Observer observer) {observers.remove(observer);}@Overridepublic void notifyObservers(String exercisePlan) {observers.forEach(observer -> observer.update(exercisePlan));}// 改变演习计划并通知观察者public void changeExercisePlan(String newPlan) {notifyObservers(newPlan);}
}

第四步,新建了一个TroopCommander 类, 实现了Observer 接口,负责接收演习计划的更新,并通知其下属的部队。

// 具体观察者:团长
public class TroopCommander implements Observer {private String name;private List<Troop> troops;public TroopCommander(String name) {this.name = name;this.troops = new ArrayList<>();}public void addTroop(Troop troop) {troops.add(troop);}@Overridepublic void update(String exercisePlan) {System.out.println(name + "收到指挥中心的命令:" + exercisePlan + "。并通知全体部队开始执行计划!");for (Troop troop : troops) {troop.executePlan(exercisePlan);}}
}

第五步,再次创建一个观察者,定义执行计划的方法,用于执行具体的演习计划。

// 观察者:执行具体的演习计划
public interface Troop {void executePlan(String plan);
}

第六步,创建具体部队观察者,实现了 Troop 接口,负责执行具体的演习计划。

// 具体观察者:部队
public class CampTroop implements Troop {private String name;public CampTroop(String name) {this.name = name;}@Overridepublic void executePlan(String plan) {System.out.println(name + "收到!执行计划:" + plan);}
}

第七步,在客户端代码中使用观察者来执行朱日和军演指挥流程。

// 测试类
public class ZhuRiHeExerciseSystem {public static void main(String[] args) {ZhuRiHeCommandCenter commandCenter = new ZhuRiHeCommandCenter();TroopCommander reedCommander = new TroopCommander("红军");TroopCommander buleCommander = new TroopCommander("蓝军");reedCommander.addTroop(new CampTroop("一营"));reedCommander.addTroop(new CampTroop("二营"));buleCommander.addTroop(new CampTroop("三营"));buleCommander.addTroop(new CampTroop("四营"));commandCenter.registerObserver(reedCommander);commandCenter.changeExercisePlan("执行方案A");commandCenter.removeObserver(reedCommander);commandCenter.registerObserver(buleCommander);commandCenter.changeExercisePlan("执行方案B");}
}

从结果上看,利用观察者模式,红蓝双方都准备接收到了来自指挥中心传达的命令。
在这里插入图片描述

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 海外短剧开源系统UNIAPP源码(支持多语言/海外支付/快捷登录)
  • 【Docker 系列】学习路线
  • Xcode多任务处理指南:释放iOS应用的并发潜能
  • 快速上手文心一言:让创作更轻松
  • TensorFlow系列:第五讲:移动端部署模型
  • 探索Java网络编程精髓:UDP与TCP的实战魔法!
  • 2024年高职云计算实验室建设及云计算实训平台整体解决方案
  • 三级_网络技术_13_局域网技术基础及应用
  • android 居中对齐
  • kafka部署以及常用命令详细总结
  • 【Docker系列】Docker 的基本概念和优势,以及在应用程序开发中的实际应用
  • 期货量化交易客户端开源教学第一节——交易服务器的安装
  • 【GameFramework扩展应用】6-3、GameFramework框架增加日志保存功能
  • 如何压缩pdf文件大小,怎么压缩pdf文件大小
  • 虚幻引擎ue5如何调节物体锚点
  • css系列之关于字体的事
  • docker容器内的网络抓包
  • eclipse(luna)创建web工程
  • iOS小技巧之UIImagePickerController实现头像选择
  • js算法-归并排序(merge_sort)
  • python学习笔记-类对象的信息
  • Quartz实现数据同步 | 从0开始构建SpringCloud微服务(3)
  • Terraform入门 - 3. 变更基础设施
  • 精彩代码 vue.js
  • 理解 C# 泛型接口中的协变与逆变(抗变)
  • 聊聊flink的TableFactory
  • 十年未变!安全,谁之责?(下)
  • 吐槽Javascript系列二:数组中的splice和slice方法
  • 详解NodeJs流之一
  • 追踪解析 FutureTask 源码
  • Hibernate主键生成策略及选择
  • ​ 全球云科技基础设施:亚马逊云科技的海外服务器网络如何演进
  • ​TypeScript都不会用,也敢说会前端?
  • # 安徽锐锋科技IDMS系统简介
  • $.type 怎么精确判断对象类型的 --(源码学习2)
  • (7)摄像机和云台
  • (Mirage系列之二)VMware Horizon Mirage的经典用户用例及真实案例分析
  • (Redis使用系列) Springboot 在redis中使用BloomFilter布隆过滤器机制 六
  • (阿里云万网)-域名注册购买实名流程
  • (超简单)使用vuepress搭建自己的博客并部署到github pages上
  • (大众金融)SQL server面试题(1)-总销售量最少的3个型号的车及其总销售量
  • (附源码)springboot社区居家养老互助服务管理平台 毕业设计 062027
  • (教学思路 C#之类三)方法参数类型(ref、out、parmas)
  • (每日一问)设计模式:设计模式的原则与分类——如何提升代码质量?
  • (免费分享)基于springboot,vue疗养中心管理系统
  • (南京观海微电子)——COF介绍
  • (四) 虚拟摄像头vivi体验
  • (四)模仿学习-完成后台管理页面查询
  • (转)编辑寄语:因为爱心,所以美丽
  • (自适应手机端)响应式新闻博客知识类pbootcms网站模板 自媒体运营博客网站源码下载
  • .NET 应用启用与禁用自动生成绑定重定向 (bindingRedirect),解决不同版本 dll 的依赖问题
  • .NET 直连SAP HANA数据库
  • .net访问oracle数据库性能问题
  • .net专家(张羿专栏)
  • /deep/和 >>>以及 ::v-deep 三者的区别