观察者模式的实现

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

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

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

观察者模式的概念

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

为什么选择观察者模式?

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot实战:枚举类型转换问题

1.在controller层中完成service注入 2.调用业务层进行查询所有房间类型标签 Tag(name "标签管理") RestController RequestMapping("/admin/label") public class LabelController {Autowiredprivate LabelInfoService service;Operation(summary &qu…

dm-verity hashtree的结构

参考了&#xff1a;实现 dm-verity | Android Open Source Project (google.cn)。基于这个添加了一层原始数据&#xff0c;便于理解。 结构图如下&#xff1a; 对hashtree结构图的解释&#xff1a; dev data&#xff1a;表示我们的分区数据。这里我们将dev data按照指定的大…

【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已经包…

学习C++,应该循序渐进的看哪些书?

学习C是一个循序渐进的过程&#xff0c;需要根据自己的基础和目标来选择合适的书籍。以下是一个推荐的学习路径&#xff0c;包含了从入门到进阶的书籍&#xff1a; 1. 入门阶段 《C Primer Plus 第6版 中文版》 推荐理由&#xff1a;这本书同样适合C零基础的学习者&#xff0…

中国蚁剑的安装(附文件)

1.下载压包&#xff08;注意两个都要下载&#xff09; 我先挂几个月&#xff0c;后续怕找不到的话&#xff0c;就自己保存网盘 链接:https://pan.baidu.com/s/1bhBe6a1_5VFYUY35XG1N9Q?pwdx9gp 提取码:x9gp 链接:https://pan.baidu.com/s/1u8CMkOORRVpCI2zJysJPQQ?pwdx9gp …

java Web学习笔记(三)

文章目录 1. 前置知识2. Vue使用vite构建项目SFC入门使用ref和.value体会响应式数据&#xff08;使用ES6和setup&#xff09; 3. Vue视图渲染技术及其语法模板语法&#xff1a;命令插值表达式渲染双标><中的文本&#xff08;还挺可爱&#xff09;属性渲染命令事件渲染命令…

内网对抗-基石框架篇域树林域森林架构信任关系多域成员层级信息收集环境搭建

知识点&#xff1a; 1、基石框架篇-域树&域林架构-权限控制-用户和网络 2、基石框架篇-域树&域林架构-环境搭建-准备和加入 3、基石框架篇-域树&域林架构-信息收集-手工和工具1、工作组(局域网) 将不同的计算机按照功能分别列入不同的工作组。想要访问某个部门的…

24/7/12总结

axios Axios 是一个基于 promise 网络请求库&#xff0c;作用于node.js 和浏览器中。 它是 isomorphic 的(即同一套代码可以运行在浏览器和node.js中)。在服务端它使用原生 node.js http 模块, 而在客户端 (浏览端) 则使用 XMLHttpRequests。 get请求: <script>function…

WordPress 主题技巧:给文章页增加“谁来过”模块。

模块功能&#xff1a; 我个人目前在做一个电影类的网站&#xff0c;在开发文章页的模版时候&#xff0c;突然觉得给文章页增加一个“谁对本电影感兴趣”的功能模块可能会比较有趣&#xff0c;这个功能有点类似于‘足迹’的感觉&#xff0c;用户可以通过这个功能&#xff0c;发…

C# Winform 系统方案目录的管理开发

在做一个中等复杂程度项目时&#xff0c;我们通常有系统全局配置&#xff0c;还要有对应的方案目录的管理和更新。 比如我们有如下需求&#xff1a;开发一个方案管理&#xff0c;可以新建、打开和保存方案&#xff0c;同时还需要保存方案中的各种文件。我设计的采用目录管理和…

短视频SEO矩阵系统:源码开发与部署全攻略

在数字化时代&#xff0c;短视频已成为人们获取信息、娱乐休闲的重要方式。随着短视频平台的兴起&#xff0c;如何让自己的内容在众多视频中脱颖而出&#xff0c;成为每个创作者和内容运营者关注的焦点。本文将为您深入解析短视频SEO矩阵系统的源码开发与部署&#xff0c;助您在…

Flink异常:org/apache/hadoop/hive/ql/parse/SemanticException

在flink项目中跑 上面这段代码出现如下这个异常&#xff0c; java.lang.NoClassDefFoundError: org/apache/thrift/TException 加上下面这个依赖后不报错 <dependency> <groupId>org.apache.thrift</groupId> <artifactId>libthrift</artifactId…

PostgreSQL(二十二)缓冲区管理器

目录 一、缓冲区概述 1、缓冲区结构 2、buffer_tag结构 3、Backend进程读取操作 4、写脏块 二、缓冲区管理器结构 1、第一层&#xff1a;Buffer Table layer&#xff08;缓冲区表层&#xff09; 2、第二层&#xff1a;Buffer Descriptor Layer&#xff08;缓冲区描述层…

有必要把共享服务器升级到VPS吗?

根据自己的需求来选择是否升级&#xff0c;虚拟专用服务器 (VPS) 是一种托管解决方案&#xff0c;它以低得多的成本提供专用服务器的大部分功能。使用 VPS&#xff0c;您的虚拟服务器将与在其上运行的其他虚拟服务器共享硬件服务器的资源。但是&#xff0c;与传统的共享托管&am…

用python识别二维码(python实例二十三)

目录 1.认识Python 2.环境与工具 2.1 python环境 2.2 Visual Studio Code编译 3.识别二维码 3.1 代码构思 3.2 代码实例 3.3 运行结果 4.总结 1.认识Python Python 是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。 Python 的设计具有很强的可读性&…

Hadoop3:HDFS-通过配置黑白名单对集群进行扩缩容,并实现数据均衡(实用)

一、集群情况介绍 我的本地虚拟机&#xff0c;一共有三个节点&#xff0c;hadoop102、hadoop103、hadoop104 二、白名单 创建白名单文件whitelist&#xff0c;通过白名单的配置&#xff0c;只允许集群包含102和103两台机器可以存储数据&#xff0c;104无法存储数据。 需求 …

数据结构(4.2)——朴素模式匹配算法

字符串模式匹配 在主串中找到模式串相同的子串&#xff0c;并返回其所在的位置。 子串和模式串的区别 子串&#xff1a;主串的一部分&#xff0c;一定存在 模式串&#xff1a;不一定能在主串中找到 字符串模式匹配 朴素模式匹配算法 主串长度为n&#xff0c;模式串长度为…

js 请求blob:https:// 图片

方式1 def get_file_content_chrome(driver, uri):result driver.execute_async_script("""var uri arguments[0];var callback arguments[1];var toBase64 function(buffer){for(var r,nnew Uint8Array(buffer),tn.length,anew Uint8Array(4*Math.ceil(t/…

Oracle数据库加密与安全

Wallet简介&#xff1a; Oracle Wallet(即内部加密技术TDE( Transparent DataEncryption&#xff09; TDE是 Oracle10gR2中推出的一个新功能,使用时要保证Oracle版本是在10gR2或者以上 Wallet配置&#xff1a; 1.创建一个新目录&#xff0c;并指定为Wallet目录 /home/oracle…

根据脚手架archetype快速构建spring boot/cloud项目

1、找到archetype&#xff0c;并从私仓下载添加archetype到本地 点击IDEA的file&#xff0c;选择new project 选择maven项目&#xff0c;勾选create from archetype 填写archetype信息&#xff0c;&#xff08;repository填写私仓地址&#xff09; 2、选择自定义的脚手架arche…