设计模式-观察者模式

观察者模式

● 行为设计模式,允许对象存在的一种一对多的关系
● 当一个对象发生变化,所有依赖他的对象都会得到通知并自动更新。
● 在这种模式中,发生状态变化的对象叫作“主题”,依赖他的对象被称为“观察者”

观察者例子的简单实践

假设我们有一个气象站 (WeatherStation),需要向许多不同的显示设备(如手机App、网站、电子屏幕 等)提供实时天气数据。
在这里插入图片描述

  1. 创建主题接口
package com.hillky.desgin_learn.observer;public interface Subject {void registerObserver(Observer o);void removeObserver(Observer o);void notifyObservers();
}
  1. 创建一个Observer接口,表示观察者:
package com.hillky.desgin_learn.observer;public interface Observer {void update(float temperature, float humidity, float pressure);
}
  1. 创建一个具体的主题,如WeatherStation,实现Subject接口:
package com.hillky.desgin_learn.observer;import java.util.ArrayList;public class WeatherStation implements Subject{private ArrayList<Observer> observers;// 温度private float temperature;public WeatherStation() {observers=new ArrayList<>();}public void setTemperature(float temperature) {this.temperature = temperature;// 通知观察者notifyObservers();}@Overridepublic void registerObserver(Observer o) {observers.add(o);}@Overridepublic void removeObserver(Observer o) {observers.remove(o);}@Overridepublic void notifyObservers() {for (Observer observer : observers) {observer.update(temperature);}}
}
  1. 创建具体的观察者,如PhoneApp,,WebApp,实现Observer接口:
package com.hillky.desgin_learn.observer;public class WebApp implements Observer{@Overridepublic void update(float temperature) {System.out.println("WebApp修改了温度===>"+temperature);}}package com.hillky.desgin_learn.observer;public class PhoneApp implements Observer{@Overridepublic void update(float temperature) {System.out.println("PhoneApp修改了温度===>"+temperature);}}
  1. 创建一个WeatherStation实例并向其注册PhoneApp观察者。当 WeatherStation的数据发生变化时,PhoneApp会收到通知并更新自己的显示
package com.hillky.desgin_learn.observer;public class Client {public static void main(String[] args) throws InterruptedException {//创建主题WeatherStation weatherStation=new WeatherStation();//创建观察者Observer phoneApp = new PhoneApp();Observer webApp = new WebApp();//主题绑定观察者weatherStation.registerObserver(phoneApp);weatherStation.registerObserver(webApp);//气象站更新weatherStation.setTemperature(26.5F);Thread.sleep(5000);weatherStation.setTemperature(32.5F);}
}

● 观察者和主题者之间互相解耦
● 可以动态增加或删除观察者
● 主题和观察者之间的通信是自动的(主题更新,观察者自动更新)

使用场景

● 股票行情应用(股票价格发生变化,通知订阅的投资者)
● 网络聊天室
● 订阅系统

电商系统观察者模式实践

假设我们有一个电商系统,当某件商品有促销活动时,需要通知所有订阅了该商品的 用户。在这个例子中,商品是主题,用户是观察者,其代码逻辑和第一节的例子不能 说完全一样,也基本是一模一样

  1. 定义一个Subject接口,表示主题:
package com.hillky.desgin_learn.observer.mall;public interface Subject {void registerObserver(Observer o);void removeObserver(Observer o);void notifyObservers();
}
  1. 创建一个Observer接口,表示观察者
package com.hillky.desgin_learn.observer.mall;public interface Observer {void update(String discountInfo);
}
  1. 创建一个具体的主题,如Product,实现Subject接口
package com.hillky.desgin_learn.observer.mall;import java.util.ArrayList;public class Product implements Subject{private ArrayList<Observer> observers;// 折扣消息private String discountInfo;public Product() {observers=new ArrayList<>();}public void discountChanged() {notifyObservers();}public void setDiscountInfo(String discountInfo) {this.discountInfo = discountInfo;discountChanged();}@Overridepublic void registerObserver(Observer o) {observers.add(o);}@Overridepublic void removeObserver(Observer o) {observers.remove(o);}@Overridepublic void notifyObservers() {for (Observer observer : observers) {observer.update(discountInfo);}}
}
  1. 创建一个具体的观察者,如User,实现Observer接口:
package com.hillky.desgin_learn.observer.mall;public class User  implements Observer{private String userName;private String discountInfo;private Subject product;public User(String userName, Subject product) {this.userName = userName;this.product = product;}public void display() {System.out.println("用户 " + userName + " 收到促销通知: " + discountInfo);}@Overridepublic void update(String discountInfo) {this.discountInfo=discountInfo;display();}
}
  1. 以创建一个Product实例并向其注册User观察者。当Product的促销信息 发生变化时,User会收到通知并显示促销信息。
package com.hillky.desgin_learn.observer.mall;public class Client {public static void main(String[] args) {Product product = new Product();User user1 = new User("张三", product);User user2 = new User("李四", product);// 模拟商品促销信息更新product.setDiscountInfo("本周末满100减50");product.setDiscountInfo("双十一全场5折");}
}

发布订阅

● 发布-订阅模式和观察者模式都是用于实现对象间的松耦合通信的设计模式
● 可以将发布-订阅模式看作是 观察者模式的一种变体或扩展。

区别

● 观察者模式定义了一种一对多的依赖关系,当一个对象(被观察者)的状态发生变化 时,所有依赖于它的对象(观察者)都会得到通知并自动更新。
● 发布-订阅模式(生产者和消费者)与观察者模式类似,但它们之间有一个关键区 别:发布-订阅模式引入了一个第三方组件(通常称为消息代理或事件总线),该组 件负责维护发布者和订阅者之间的关系。

实践

  1. 订阅者接口定义
package com.hillky.desgin_learn.observer.release;public interface Subscriber {void onEvent(String event);
}
  1. 实现一个具体的订阅者
package com.hillky.desgin_learn.observer.release;public class ConcreteSubscriber implements Subscriber{@Overridepublic void onEvent(String event) {System.out.println("收到事件: " + event);}
}
  1. 创建消息总线类(消息的中间件)
package com.hillky.desgin_learn.observer.release;import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;public class EventBus {// 使用一个map维护,消息类型和该消息的订阅者private Map<String, List<Subscriber>> subscribers = new HashMap<>();public void subscribe(String eventType, Subscriber subscriber) {subscribers.computeIfAbsent(eventType, k -> new ArrayList<>()).add(subscriber);}public void unsubscribe(String eventType, Subscriber subscriber) {List<Subscriber> subs = subscribers.get(eventType);if (subs != null) {subs.remove(subscriber);}}public void publish(String eventType, String event) {List<Subscriber> subs = subscribers.get(eventType);if (subs != null) {for (Subscriber subscriber : subs) {subscriber.onEvent(event);}}}
}
  1. 测试使用
package com.hillky.desgin_learn.observer.release;public class Client {public static void main(String[] args) {EventBus eventBus = new EventBus();Subscriber subscriber1 = new ConcreteSubscriber();Subscriber subscriber2 = new ConcreteSubscriber();// 订阅事件eventBus.subscribe("eventA", subscriber1);eventBus.subscribe("eventA", subscriber2);// 发布事件eventBus.publish("eventA", "这是事件A的内容");// 取消订阅eventBus.unsubscribe("eventA", subscriber1);// 再次发布事件eventBus.publish("eventA", "这是事件A的新内容");}
}

源码使用(结合Gpt找例子)

JDK中的使用

● java.util.Observable类实现了主题(Subject)的功能,而java.util.Observer接口则 定义了观察者(Observer)的方法。
● 通过调用Observable对象的notifyObservers()方法,可以通知所有注册的Observer 对象,让它们更新自己的状态。

Guava中的消息总线

● Guava 库中的 EventBus 类提供了一个简单的消息总线实现,可以帮助您在 Java 应用程序中实现发布-订阅模式。

进阶

异步非阻塞模型
同步阻塞的实现方式。观察者和被观察者代码在同一个 线程内执行,被观察者一直阻塞,直到所有的观察者代码都执行完成之后,才执行后续的代码。利用多线程替换遍历通知

实践

  1. 创建观察者接口
package com.hillky.desgin_learn.observer.sync;public interface Observer {void update(String message);
}
  1. 被观察者的接口
package com.hillky.desgin_learn.observer.sync;public interface Observable {void addObserver(Observer observer);void removeObserver(Observer observer);void notifyObservers(String message);
}
  1. 实现一个具体的被观察者类 Subject
package com.hillky.desgin_learn.observer.sync;import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class Subject implements Observable{private List<Observer> observers;private ExecutorService executorService;public Subject() {observers=new ArrayList<>();executorService= Executors.newCachedThreadPool();}@Overridepublic void addObserver(Observer observer) {observers.add(observer);}@Overridepublic void removeObserver(Observer observer) {observers.remove(observer);}@Overridepublic void notifyObservers(String message) {for (Observer observer : observers) {executorService.submit(() -> observer.update(message));}}public void setMessage(String message) {notifyObservers(message);}}
  1. 实现具体的观察者ConcreteObserver
package com.hillky.desgin_learn.observer.sync;public class ConcreteObserver implements Observer {private String name;public ConcreteObserver(String name) {this.name = name;}@Overridepublic void update(String message) throws InterruptedException {Thread.sleep(5000);System.out.println(name + " received message: " + message);}
}
  1. 简单示例调用
package com.hillky.desgin_learn.observer.sync;public class Client {public static void main(String[] args) throws InterruptedException {Subject subject = new Subject();ConcreteObserver observer1 = new ConcreteObserver("Observer 1");ConcreteObserver observer2 = new ConcreteObserver("Observer 2");ConcreteObserver observer3 = new ConcreteObserver("Observer 3");subject.addObserver(observer1);subject.addObserver(observer2);subject.addObserver(observer3);subject.setMessage("Hello, observers!");}}

在这个示例中,我们使用了 ExecutorService 的线程池来实现异步非阻塞的通知。 每个观察者更新操作都将作为一个任务提交给线程池并异步执行。

跨进程通信

● 不管是同步阻塞实现方式还是异步非阻塞实现方式,都是进程内的实现方式。
● 跨进程通信可以引入中间件(消息队列)来实现,被观察者和观察者解耦更加彻底,两部分的耦合更小

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【VS】InstallerProjects.vsix下载 Microsoft Visual Studio Installer Projects (2022)

InstallerProjects.vsix 是微软官方提供的winform程序打包工具&#xff0c;但是国内下载安装有时候比较慢。虽然只有5m左右&#xff0c;但是国内就是下载不下来。现将官网地址和下载后的百度网盘共享地址展示如下&#xff1a;方便大家使用 官方地址&#xff1a;https://market…

再JAVA中如何使用qsort对类进行排序?

目录 结论&#xff1a; 解析&#xff1a; 结论&#xff1a; import java.util.Arrays;class Person implements Comparable<Person>{public String name;public int age;public Person(String name, int age) {this.name name;this.age age;}Overridepublic Stri…

# Lua与C++交互(二)———— 交互

C 调用lua 基础调用 再来温习一下 myName “beauty girl” C想要获取myName的值&#xff0c;根据规则&#xff0c;它需要把myName压入栈中&#xff0c;这样lua就能看到&#xff1b;lua从堆栈中获取myName的值&#xff0c;此时栈顶为空&#xff1b;lua拿着myName去全局表中查…

通讯录管理系统

1、简介 最近在学习C&#xff0c;通过观看黑马的教程进行学习&#xff0c;本文主要对通讯录管理系统的内容进行代码复现笔记&#xff0c;方便以后复习与使用&#xff0c;也方便大家复制使用&#xff0c;节约学习时间。 2、显示函数界面 2.1 函数框架 #include<iostream&…

冠达管理:非银金融是什么?

非银金融&#xff08;Non-banking Financial Institutions&#xff0c;简称非银&#xff09;是指除了传统的银行以外的其他金融机构。与银行不同的是&#xff0c;非银金融机构没有颁发钱银的权利&#xff0c;但在金融市场中发挥着重要的效果。在全球范围内&#xff0c;非银金融…

Spring Boot 集成 WebSocket 实现服务端推送消息到客户端

WebSocket 简介 WebSocket 协议是基于 TCP 的一种新的网络协议&#xff0c;它实现了浏览器与服务器全双工&#xff08;full-duplex&#xff09;通信—允许服务器主动发送信息给客户端&#xff0c;这样就可以实现从客户端发送消息到服务器&#xff0c;而服务器又可以转发消息到客…

MySQL不停重启问题

MySQL不停的自动杀掉自动重启 看一下log日志 my.cnf 里配置的 log_error /var/log/mysqld.log vim /var/log/mysqld.log 报的错误只是 [ERROR] Cant start server: Bind on TCP/IP port: Address already in use [ERROR] Do you already have another mysqld server …

数据结构之——(手撕)顺序表

本章会介绍的知识点如下图&#xff1a; 1&#xff1a; 顺序表的概念&#xff1a;顺序表是用一段物理地址连续的存储单元依次存储数据的线性结构&#xff0c;通常我们使用数组来表示&#xff0c;对数组进行增删查改。 顺序表的结构&#xff1a;逻辑结构与物理结构都是内存中一块…

⛳ Docker 安装 MySQL

&#x1f38d;目录 ⛳ Docker 安装 MySQL&#x1f69c; 一、搜索 mysql , 查看版本&#x1f3a8; 二、拉取mysql镜像&#x1f463; 三、建立容器的挂载文件&#x1f9f0; 四、创建mysql配置文件&#xff0c;my.conf&#x1f3ed; 五、根据镜像产生容器&#x1f381; 六、远程连…

node_modules.cache是什么东西

一开始没明白这是啥玩意&#xff0c;还以为是npm的属性&#xff0c;网上也没说过具体的来源出处 .cache文件的产生是由webpack4的插件cache-loader生成的&#xff0c;node_modules里下载了cache-loader插件&#xff0c;很多朋友都是vuecli工具生成的项目&#xff0c;内置了这部…

elelementui组件

一、按钮 1、按钮样式 使用type、plain、round和circle属性来定义 Button 的样式。 2、主要代码 <el-row><el-button>默认按钮</el-button><el-button type"primary">主要按钮</el-button><el-button type"success">…

【计算机网络】日志与守护进程

文章目录 日志日志的创建logmessage 函数日志左边部分实现日志右边部分实现 完整代码log.hpp(整体实现)err.hpp (错误信息枚举&#xff09; 守护进程PGID SID TTY 的介绍shell中控制进程组的方式结论 为什么要有守护进程存在&#xff1f;守护进程的创建使用守护进程的条件守护进…

2023国赛数学建模A题B题C题D题资料思路汇总 高教社杯

本次比赛我们将会全程更新思路模型及代码&#xff0c;大家查看文末名片获取 之前国赛相关的资料和助攻可以查看 2022数学建模国赛C题思路分析_2022年数学建模c题思路_UST数模社_的博客-CSDN博客 2022国赛数学建模A题B题C题D题资料思路汇总 高教社杯_2022国赛a题题目_UST数模…

前端通信(渲染、http、缓存、异步、跨域)自用笔记

SSR/CSR&#xff1a;HTML拼接&#xff1f;网页源码&#xff1f;SEO/交互性 SSR &#xff08;server side render&#xff09;服务端渲染&#xff0c;是指由服务侧&#xff08;server side&#xff09;完成页面的DOM结构拼接&#xff0c;然后发送到浏览器&#xff0c;为其绑定状…

浅谈泛在电力物联网发展形态与技术挑战

安科瑞 华楠 摘 要&#xff1a;泛在电力物联网是当前智能电网发展的一个方向。首先&#xff0c;总结了泛在电力物联网的主要作用和价值体现&#xff1b;其次&#xff0c;从智能电网各个环节概述了物联网技术在电力领域的已有研究和应用基础&#xff1b;进而&#xff0c;构思并…

手机无人直播软件,有哪些优势?

近年来&#xff0c;随着手机直播的流行和直播带货的市场越来越大&#xff0c;手机无人直播软件成为许多商家开播带货的首选。在这个领域里&#xff0c;声音人无人直播系统以其独特的优势&#xff0c;成为市场上备受瞩目的产品。接下来&#xff0c;我们将探讨手机无人直播软件给…

基于jeecg-boot的flowable流程加签功能实现

更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码&#xff1a; https://gitee.com/nbacheng/nbcio-boot 前端代码&#xff1a;https://gitee.com/nbacheng/nbcio-vue.git 在线演示&#xff08;包括H5&#xff09; &#xff1a; http://122.227.135.243:9888 今天我…

uni-app打包后安卓不显示地图及相关操作详解

新公司最近用uni-app写app&#xff0c;之前的代码有很多问题&#xff0c;正好趁着改bug的时间学习下uni-app。 问题现象&#xff1a; 使用uni-app在浏览器调试的时候&#xff0c;地图是展示的&#xff0c;但是打包完成后&#xff0c;在app端是空白的。咱第一次写app&#xff…

视频云存储/安防监控EasyCVR视频汇聚平台分发rtsp流时,出现“用户已过期”提示该如何解决?

视频云存储/安防监控EasyCVR视频汇聚平台基于云边端智能协同&#xff0c;支持海量视频的轻量化接入与汇聚、转码与处理、全网智能分发、视频集中存储等。音视频流媒体视频平台EasyCVR拓展性强&#xff0c;视频能力丰富&#xff0c;具体可实现视频监控直播、视频轮播、视频录像、…

2023企业Hyper-V备份解决方案!

虚拟技术已成为IT基础设施的核心元素&#xff0c;企业长期依赖虚拟机&#xff08;VM&#xff09;为应用程序提供工作负载。Hyper-V是一款广受欢迎的虚拟化平台&#xff0c;多年来已日臻完善&#xff0c;并在各类规模的公司中得到广泛应用。 随着虚拟机使用的普及&…