观察者模式的实现

news2024/11/15 13:04:20

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

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

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

观察者模式的概念

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

为什么选择观察者模式?

  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<>();

    @Override
    public void registerObserver(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public 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);
    }
    @Override
    public 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;
    }

    @Override
    public 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");
   }
}

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1922616.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vue和Element UI 路由跳转,侧边导航的路由跳转,侧边栏拖拽

首先看布局&#xff0c;因为我的用于页面显示的 <router-view> 是通过重定向定位到登陆页的&#xff0c;然后通过登陆页跳转到主页。项目中用到了点击侧边栏的跳转&#xff0c;所以记录下来&#xff0c;方便有需要的人用到~ 阐述 &#xff08;1&#xff09;.content{ di…

openharmony上传图片,并获取返回路径

适用条件&#xff1a; openharmony开发 4.0 release版本&#xff0c;对应能力API10 一直不断尝试&#xff0c;一会用官方提供的上传文件&#xff0c;一会用第三方库的axios都不行&#xff0c; 一会报错‘没权限&#xff0c;一会报错’路径错误&#xff0c;还有报错‘401参数错…

探索Java网络编程精髓:UDP与TCP的实战魔法!

Java 中提供了专门的网络编程程序包 java.net&#xff0c;提供了两种通信协议&#xff1a;UDP&#xff08;数据报协议&#xff09;和 TCP&#xff08;传输控制协议&#xff09;&#xff0c;本文对两种通信协议的开发进行详细介绍。 1 UDP 介绍 UDP&#xff1a;User Datagram Pr…

压缩pdf文件的大小,pdf档怎么压缩为最小内存

在现代工作和学习中&#xff0c;pdf文件已经成为了一种不可或缺的文件格式。它跨平台、保持格式不变的优势使其在文件传输和分享中占据了重要位置。然而&#xff0c;pdf文件往往因为包含大量图像和文本而体积较大&#xff0c;这给文件的传输和存储带来了不少困扰。本文将为你介…

不会编程怎么办?量化交易不会编程可以使用吗?

量化交易使用计算机模型程序代替人工进行交易&#xff0c;一般需要投资者自己编写程序建模&#xff0c;然后回测无误之后再进行实盘交易&#xff0c;那么不会编程的投资者能使用量化软件进行量化交易吗&#xff1f; 不会编程使用量化软件有两种方法 一种是请人代写代码&#x…

Java高频面试基础知识点整理8

干货分享&#xff0c;感谢您的阅读&#xff01;背景​​​​​​高频面试题基本总结回顾&#xff08;含笔试高频算法整理&#xff09; 最全文章见&#xff1a;Java高频面试基础知识点整理 &#xff08;一&#xff09;Java基础高频知识考点 针对人员&#xff1a; 1.全部人员都…

【三维AIGC】扩散模型LDM辅助3D Gaussian重建三维场景

标题&#xff1a;《Sampling 3D Gaussian Scenes in Seconds with Latent Diffusion Models》 来源&#xff1a;Glasgow大学&#xff1b;爱丁堡大学 连接&#xff1a;https://arxiv.org/abs/2406.13099 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何…

Guava LocalCache源码分析:LocalCache生成

Guava LocalCache源码分析&#xff1a;Cache生成 版本LocalCache参数说明Cache构建过程LocalCache介绍LocalCache实例化将builder中的属性赋值到LocalCache中分段 LocalCache为guava本地缓存的解决方案&#xff0c;提供了基于容量&#xff0c;时间和引用的缓存回收方式&#xf…

Spring MVC入门3

看完这篇博客你能学到什么 理解JSON的使用理解注解PathVariable理解解注解RequestPart理解cookie和Session的基本概念理解cookie和Session的区别 如果想真正掌握&#xff0c;还需要自己勤加练习。 正文 JSON JSON概念 JSON&#xff1a;JavaScript Object Notation 【JavaS…

免费长效IP在业务场景中的深度应用解析

在数字化竞赛的跑道上&#xff0c;每一秒的都至关重要&#xff0c;而免费长效IP&#xff0c;不仅为企业减少了运营成本&#xff0c;更在数据安全与访问效率上筑起了一道坚实的保护线。然而&#xff0c;面对市场上琳琅满目的代理服务&#xff0c;如何挑选出能应对各种业务场景的…

【JAVA poi-tl-ext 富文本转word】

富文本转word 环境使用poi-tl-ext的原因富文本转word代码 环境 jdk 1.8 <dependency><groupId>io.github.draco1023</groupId><artifactId>poi-tl-ext</artifactId><version>0.4.16</version> </dependency>poi-tl-ext已经包…

ES 慢上游响应问题优化在用户体验场景中的实践

在抖音亿级日活流量的情况下&#xff0c;每天收到的用户反馈也是大量的&#xff0c;而用户反馈对于产品的发展与未来是至关重要的&#xff0c;因此用户体验管理平台&#xff08;简称VoC&#xff09;就应运而生&#xff0c;VoC 平台旨在通过技术平台化的方式&#xff0c;结合反馈…

字体反爬之自动化通过字体文件生成映射字典

1、首先找到以.ttf结尾的字体文件&#xff0c;下载下来&#xff0c;以我的字体文件sfont.ttf为例 sont.ttf下载地址https://download.csdn.net/download/lingyingdon/89534953 目前只测试了.ttf文件。如果想使用woff字体文件&#xff0c;请自行测试 2、下载分割字体文件的软件…

从汇编层看64位程序运行——参数传递的底层实现

大纲 小于等于6个参数一个参数总结 两个参数总结 三个参数总结 四个参数总结 五个参数总结 六个参数总结 大于6个参数七个参数总结 在32位系统中&#xff0c;参数的传递主要依靠栈来进行。那么64位系统上&#xff0c;是否依旧符合这个规则呢&#xff1f;答案是“不是”。64位系…

Objective-C 自定义渐变色Slider

文章目录 一、前情概要二、具体实现 一、前情概要 系统提供UISlider&#xff0c;但在开发过程中经常需要自定义&#xff0c;本次需求内容是实现一个拥有渐变色的滑动条&#xff0c;且渐变色随着手指touch的位置不同改变区域&#xff0c;类似如下 可以使用CAGradientLayer实现渐…

【Linux】Linux操作系统

Linux基本指令 os概念与定位 本节内容&#xff1a; Linux操作系统讲解 os概念与定位 操作系统&#xff08;Operating System&#xff0c;简称OS&#xff09;是管理和控制计算机硬件与软件资源的计算机程序。总的来讲&#xff0c;操作系统是一款做软硬件管理的软件。 了解操作…

springBoot(若依)集成camunda

1、下图为项目结构 2、最外层 pom引入依赖 <properties><!--camunda 标明版本&#xff0c;注意要个自己的Spring 版本匹配&#xff0c;匹配关系自行查询官网--><camunda.version>7.18.0</camunda.version> </properties> 3、common模块引入依赖 …

安卓14中Zygote初始化流程及源码分析

文章目录 日志抓取结合日志与源码分析systemServer zygote创建时序图一般应用 zygote 创建时序图向 zygote socket 发送数据时序图 本文首发地址 https://h89.cn/archives/298.html 最新更新地址 https://gitee.com/chenjim/chenjimblog 本文主要结合日志和代码看安卓 14 中 Zy…

抗量子密码算法:保障未来信息安全的新盾牌

随着量子计算的迅猛发展&#xff0c;传统加密算法正面临着前所未有的挑战。量子计算机利用量子比特的特殊性质&#xff0c;能在极短时间内破解目前广泛使用的公钥加密体系&#xff0c;如RSA、ECC等。这使得我国及全球的信息安全体系遭受严重威胁。为了应对这一挑战&#xff0c;…

知识图谱入门笔记

自学参考&#xff1a; 视频&#xff1a;斯坦福CS520 | 知识图谱 最全知识图谱综述 详解知识图谱的构建全流程 知识图谱构建&#xff08;概念&#xff0c;工具&#xff0c;实例调研&#xff09; 一、基本概念 知识图谱&#xff08;Knowledge graph&#xff09;&#xff1a;由结…