深入探究【观察者模式】:简单音乐会售票系统案例分析

文章目录

    • 1.观察者模式概述
        • 基本概念:
        • 工作原理:
    • 2.案例-音乐会抢票
      • 2.1.具体实现
        • 2.1.1.被观察者接口
        • 2.1.2.被观察者实现类
        • 2.1.3.定义观察者接口
        • 2.1.3.定义观察者实现类
        • 2.1.4.测试观察者
    • 3.总结
      • 3.1.优点和局限性
      • 3.2.思考

1.观察者模式概述

观察者模式是一种行为型设计模式,它允许对象(称为观察者)订阅另一个对象(称为被观察者或主题)的状态变化,并在状态发生变化时自动接收通知和作出相应的响应。观察者模式是一种松耦合的设计模式,使得被观察者和观察者之间的关系不会紧密耦合,从而提高了系统的灵活性和可扩展性。

基本概念:
  1. 被观察者(Subject):也称为主题或发布者,是状态的持有者,当其状态发生变化时会通知所有订阅者。被观察者通常包含注册、删除和通知观察者的方法。
  2. 观察者(Observer):也称为订阅者,是被动接收被观察者状态变化通知的对象。观察者需要实现接收通知并作出相应动作的方法。
  3. 通知(Notification):是被观察者向观察者发送的消息,用于告知观察者被观察者的状态发生了变化。
工作原理:
  1. 建立订阅关系:观察者通过订阅(注册)的方式与被观察者建立联系。被观察者维护一个观察者列表,可以动态添加或删除观察者。
  2. 状态变化通知:当被观察者的状态发生变化时,它会遍历观察者列表,依次调用每个观察者的通知方法,将状态变化的消息传递给观察者。
  3. 观察者响应:每个观察者接收到通知后,会执行预定义的更新逻辑,以便与被观察者的状态保持一致。观察者可以根据通知的内容进行相应的处理,比如更新界面、发送邮件等。
  4. 解耦合:观察者模式通过将被观察者和观察者解耦,使得它们之间的关系更加灵活和可扩展。被观察者不需要知道具体的观察者是谁,而观察者也不需要了解被观察者的具体实现细节,从而降低了对象之间的依赖关系。

2.案例-音乐会抢票

在软件开发中,设计模式是一种被广泛应用的解决方案,它们提供了解决特定问题的模板和指导原则。观察者模式是其中的一种重要模式,它允许对象之间建立一种一对多的依赖关系。当一个对象的状态发生变化时,所有依赖它的对象都会得到通知并自动更新。观察者模式的应用场景非常广泛,包括软件开发、系统设计以及实时数据处理等。为了更深入理解观察者模式的原理和应用,我们将以一个实际案例——音乐会售票系统,来进行分析和探讨。

音乐会售票系统是一个用于管理音乐会门票销售的应用程序,它提供了用户购买音乐会门票的功能,并且能够实时更新剩余门票数量,以便用户了解门票的售罄情况。

在音乐会售票系统中,观察者模式被应用于实现对门票销售情况的观察和通知功能。以下是系统中的角色和交互关系:

  1. 被观察者(Observable):音乐会售票系统充当被观察者,负责维护观察者列表,并在门票数量发生变化时通知观察者。
  2. 观察者(Observer)
    • 粉丝服务(FansService):作为观察者之一,粉丝服务负责接收到系统通知后,更新粉丝购票页面上的剩余门票数量。
    • 黄牛服务(CattleService):同样作为观察者,黄牛服务在接收到门票售罄通知后,可以采取一些特定的行动,比如通知其他黄牛或者调整策略。
  3. 交互关系
    • 用户购票时,系统会更新门票数量并通知所有观察者。
    • 粉丝服务和黄牛服务接收到通知后,根据通知内容更新自身状态或采取相应措施。
    • 观察者与被观察者之间的交互是松散耦合的,被观察者不知道具体的观察者身份,而观察者只需关注自己的业务逻辑即可。

通过观察者模式,音乐会售票系统实现了对门票销售情况的实时监控和通知,提升了系统的可维护性和扩展性,同时为用户和其他利益相关者提供了更好的用户体验和服务。

2.1.具体实现

image-20240228222155961

2.1.1.被观察者接口
/**
 * 被观察者接口
 * @author 13723
 * @version 1.0
 * 2024/1/29 10:12
 */
public interface Observable {
	/**
	 * 添加观察者
	 * @param observer 观察者
	 */
	void addObserver(Observer observer);

	/**
	 * 删除观察者
	 * @param observer 观察者
	 */
	void removeObserver(Observer observer);

	/**
	 * 通知观察者
	 * @param count 通知内容
	 */
	void notifyObserver(AtomicInteger count);
}

2.1.2.被观察者实现类

构建被观察者:ConcertTicketSalesService类的设计与实现,包括售票操作和通知观察者的功能。

/**
 *
 * 被观察者实现类
 * @author 13723
 * @version 1.0
 * 2024/1/29 10:14
 */
public class ConcertTicketSalesService implements Observable{
	private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

	/**
	 * 观察者集合
	 */
	private final List<Observer> observers = new ArrayList<>();

	public static final AtomicInteger count = new AtomicInteger(0);

	/**
	 * 添加观察者
	 * @param observer 观察者
	 */
	@Override
	public void addObserver(Observer observer) {
		this.observers.add(observer);
	}

	/**
	 * 删除观察者
	 * @param observer 观察者
	 */
	@Override
	public void removeObserver(Observer observer) {
		this.observers.remove(observer);
	}
	/**
	 * 通知观察者
	 * @param count 通知内容
	 */
	@Override
	public void notifyObserver(AtomicInteger count) {
		// 通知所有观察者
		for (Observer observer : this.observers) {
			observer.make(count);
		}
	}
	public void sale(int ticketNum){
		count.addAndGet(ticketNum);
		logger.error("原始售票数量:{}",ticketNum);
		logger.error(" --------- 开始售票 --------- ");
		notifyObserver(count);
	}
}

2.1.3.定义观察者接口
/**
 * 观察者接口
 * 观察者模式又称为发布/订阅(Publish/Subscribe)模式,在对象之间定义了一对多的依赖,
 * 这样一来,当一个对象改变状态,依赖它的对象会收到通知并自动更新触发行为
 */
public interface Observer {
	/**
	 * 观察者接收到通知后的处理逻辑
	 * @param count 通知内容
	 */
	void make(AtomicInteger count);
}
2.1.3.定义观察者实现类

FansServiceCattleService类的设计与实现,描述了粉丝和黄牛作为观察者接收通知并进行抢票的行为。

/**
 * 粉丝接收通知,开启抢票
 * @author 13723
 * @version 1.0
 * 2024/1/29 10:23
 */
public class FansService implements Observer  {
	private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

	/**
	 * 粉丝接收通知,开启抢票
	 * @param count 通知内容
	 */
	@Override
	public void make(AtomicInteger count) {
		int andDecrement = count.getAndDecrement();
		logger.error("粉丝接收通知,开启抢票,剩余票数{}",andDecrement);
	}
}

/**
 * 黄牛接收通知,开启抢票
 * @author 13723
 * @version 1.0
 * 2024/1/29 10:26
 */
public class CattleService implements Observer{
	private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

	/**
	 * 黄牛接收通知,开启抢票
	 * @param count 通知内容
	 */
	@Override
	public void make(AtomicInteger count) {
		int andDecrement = count.getAndDecrement();
		logger.error("黄牛接收通知,开启抢票,剩余票数{}",andDecrement);
	}
}

2.1.4.测试观察者
public class ObserverTest {
	private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());


	@Test
	@DisplayName("测试-观察者模式")
	public void test(){
		ArrayList<Thread> threads = new ArrayList<>();
		// 创建被观察者
		ConcertTicketSalesService concertTicketSalesService = new ConcertTicketSalesService();
		// 创建观察者(粉丝)
		for (int i = 0; i < 30; i++) {
			Thread thread = new Thread(() -> {
				FansService fansService = new FansService();
				concertTicketSalesService.addObserver(fansService);
			}, "f" + i);
			threads.add(thread);
		}
		// 创建观察者(黄牛)
		for (int i = 0; i < 10; i++) {
			Thread thread = new Thread(() -> {
				CattleService cattleService = new CattleService();
				concertTicketSalesService.addObserver(cattleService);
			}, "t" + i);
			threads.add(thread);
		}
		threads.forEach(Thread::start);
		// 被观察者开始执行卖票操作
		concertTicketSalesService.sale(100);


	}
}

image-20240228221718969

上面这段代码实现了观察者模式,用于模拟音乐会售票系统。其中,ConcertTicketSalesService是被观察者,负责售票操作,并在售票时通知所有观察者。观察者包括粉丝和黄牛,它们分别在收到通知后开启抢票。粉丝和黄牛通过实现Observer接口来接收通知,并通过Observable接口实现被观察者与观察者的交互。ObserverTest类则用于测试观察者模式的正确性,创建了30个粉丝和10个黄牛,并模拟了音乐会售票过程。

3.总结

3.1.优点和局限性

优点

  1. 松散耦合(Loose Coupling):观察者模式通过定义了一个抽象的观察者接口和被观察者对象之间的联系,使得它们可以相互独立地变化。这种松散耦合的设计使得系统更易于维护和扩展。
  2. 可扩展性(Scalability):由于观察者模式将被观察者对象与观察者对象分离,因此可以方便地增加新的观察者或者修改现有的观察者,而不需要修改被观察者对象的代码。
  3. 通知机制(Notification Mechanism):观察者模式提供了一种通知机制,使得被观察者对象发生改变时能够自动通知所有的观察者对象。这样可以确保所有相关的对象都能及时获取到最新的信息。
  4. 解耦合(Decoupling):观察者模式可以降低对象之间的耦合度,使得系统中的各个对象之间相互独立,降低了代码的复杂度。

局限性

  1. 过多的通知:如果被观察者对象频繁地发生改变,可能会导致观察者对象收到过多的通知,造成性能上的开销。
  2. 可能引发循环依赖:在某些情况下,观察者和被观察者之间可能出现循环依赖的情况,导致系统设计不合理。
  3. 难以调试:由于观察者模式中对象之间的关系比较复杂,当系统出现问题时,可能需要花费较多的时间和精力来进行调试和定位问题。
  4. 可能引起内存泄漏:如果观察者没有被正确地移除或者被长期持有,可能会导致内存泄漏问题,影响系统的性能和稳定性。

3.2.思考

观察者模式是一种强大的设计模式,能够有效地实现对象之间的解耦合和协同工作。在实际项目中,合理地应用观察者模式可以提高系统的灵活性、可维护性和可扩展性,但也需要根据具体情况来权衡其利弊,避免滥用和不必要的复杂性。在下面几个方面观察者模式发挥着很重要的作用

  1. 事件驱动架构:观察者模式可以作为构建事件驱动架构的基础之一。通过将各个模块之间的交互建立在事件的发布与订阅之上,可以实现系统的高内聚、低耦合,使得系统更加灵活和可扩展。
  2. 异步通信:观察者模式可以与异步通信结合,实现异步事件处理。通过消息队列或者异步任务,观察者可以在收到通知后异步处理事件,提高系统的并发能力和响应速度。
  3. 领域驱动设计(DDD):在领域驱动设计中,观察者模式可以用于实现领域事件的发布与订阅。各个领域对象可以作为观察者,订阅感兴趣的领域事件,从而实现领域对象之间的解耦合和协同工作。
  4. 消息传递:观察者模式可以被用作消息传递的机制。不同模块之间的消息交互可以通过观察者模式实现,从而简化系统的通信方式,提高系统的灵活性和可维护性。

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

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

相关文章

动态规划(算法竞赛、蓝桥杯)--混合背包DP

1、B站视频链接&#xff1a;E14 背包DP 混合背包_哔哩哔哩_bilibili #include <bits/stdc.h> using namespace std; const int N1010,M10000; int a[M],b[M],c[M];//体积、价值、类型 int f[N];int main(){int n,m,v,w,s;cin>>n>>m;int num1;for(int i1;i&…

精准杜绝医疗设备漏费的智慧防线

19339904493&#xff08;康&#xff09; 医疗设备漏费管理系统&#xff0c;如同医疗设备的智慧守望者&#xff0c;时刻守护着患者的权益与医院的利益。它运用先进的人工智能算法&#xff0c;深度读取设备内部图像与项目信息&#xff0c;通过深度学习图像并分析患者的检查部位、…

如何保护服务器的安全

互联网的迅速发展&#xff0c;让很多企业都很重视网络技术的使用&#xff0c;但是网络的传播速度比较快&#xff0c;同时容易造成数据、隐私方面的泄露现在每个企业基本有自己的服务器。有几点需要注意&#xff0c;可以参考&#xff1a; 1.基础密码安全 最基本的安全就是密码安…

Docker数据卷-自定义镜像

一.数据卷 1.1数据卷的基本使用 数据卷是一个特殊的目录&#xff0c;用于在Docker容器中持久化和共享数据。 数据卷的主要特点包括&#xff1a; 数据持久性&#xff1a;数据卷允许您在容器的生命周期之外保持数据的持久性。即使容器被删除&#xff0c;数据卷中的数据依然存在&…

礼遇派兑|神工坊龙年豪礼大放送,千元惊喜等你来领

新年伊始 万象更新 转眼间 已全面复工复学啦&#xff01; 前方警告⚠️&#xff1a;“年后再说”已无退路 万千“子涵”在线求助 别担心&#xff01;神工坊替你解决&#xff01; 神工坊高性能工业仿真平台 以国家超级计算无锡中心 丰富的软件资源和海量的硬件资源为支撑…

接口测试实战--mock测试、日志模块

一、mock测试 在前后端分离项目中,当后端工程师还没有完成接口开发的时候,前端开发工程师利用Mock技术,自己用mock技术先调用一个虚拟的接口,模拟接口返回的数据,来完成前端页面的开发。 接口测试和前端开发有一个共同点,就是都需要用到后端工程师提供的接口。所以,当…

本届挑战赛季军方案:构建由大模型辅助的基于多模态数据融合的异常检测、根因诊断和故障报告生成系统

DDopS团队荣获本届挑战赛季军。该团队来自中山大学计算机学院Intelligent DDS 实验室。实验室主要方向为云计算、智能运维(AIOps)、软件定义网络、分布式软件资源管理与优化、eBPF 性能监控与优化等。 选题分析 基于对竞赛数据的洞察和对时代趋势的考量&#xff0c;我们尝试应…

苹果Vision Pro芯片级拆解:339S01186传感器协处理器,电源管理芯片:343S00627、343S00628、343S00629

2月2日&#xff0c;苹果官方发售Vision Pro后&#xff0c;引发了抢购潮&#xff0c;产品“秒光”&#xff0c;甚至将起售价 3499 美元一度炒到近 9 万元人民币的代购价。 日前知名维修网站iFixit又一次“首拆”了苹果Vision Pro&#xff0c;每一块电路板、每一颗螺丝钉、每一颗…

阿里云4核16G服务器多少钱?幻兽帕鲁配置报价

2024阿里云幻兽帕鲁专用服务器价格表&#xff1a;4核16G幻兽帕鲁专用服务器26元一个月、149元半年&#xff0c;默认10M公网带宽&#xff0c;8核32G幻兽帕鲁服务器10M带宽价格90元1个月、271元3个月。阿里云提供的Palworld服务器是ECS经济型e实例&#xff0c;CPU采用Intel Xeon …

FPGA高端项目:FPGA基于GS2971的SDI视频接收转HDMI输出,提供3套工程源码和技术支持

目录 1、前言免责声明 2、相关方案推荐本博已有的 SDI 编解码方案本方案的SDI图像缩放应用本方案的SDI纯verilog图像缩放视频拼接应用本方案的SDI HLS图像缩放视频拼接应用本方案的SDI视频编码动态字符叠加输出应用本方案的SDI视频编码多路视频融合视频叠加应用本方案的SDI视频…

npm 最新淘宝镜像配置 + nrm工具配置及使用

一、前言 npm 淘宝镜像已经从 registry.npm.taobao.org 切换到了 registry.npmmirror.com &#xff08;HTTPS 证书到期不能用了&#xff09; 二、直接命令配置 1、执行以下命令即可切换淘宝源 npm config set registry https://registry.npmmirror.com/2、执行以下命令即可…

学不动系列-eslint

ESLint 介绍在最简单的项目使用eslint,包括eslint的vscode插件的使用&#xff0c;自动化格式代码&#xff0c;自动化修复代码&#xff0c;和webpack&#xff0c;vite的配合使用 单独使用 第一步&#xff1a;构建一个空项目 npm init -y 在根目录新建文件./src/app.js&#…

C++重点---STL简介

顾得泉&#xff1a;个人主页 个人专栏&#xff1a;《Linux操作系统》 《C从入门到精通》 《LeedCode刷题》 键盘敲烂&#xff0c;年薪百万&#xff01; 一、STL简介 STL&#xff08;Standard Template Library&#xff09;是C标准库中的一个重要组成部分&#xff0c;它提供了…

跳跃游戏Ⅱ

问题 给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。 每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说&#xff0c;如果你在 nums[i] 处&#xff0c;你可以跳转到任意 nums[i j] 处: 0 < j < nums[i] i j < n 返回到达 nums[n - …

SpringBoot整合rabbitmq-直连队列,没有交换机(一)

说明&#xff1a;本文章只是springboot和rabbitmq的直连整合&#xff0c;只使用队列生产和消费消息&#xff0c;最简单整合&#xff01; 工程图&#xff1a; A.总体pom.xml <?xml version"1.0" encoding"UTF-8"?><project xmlns"http://…

压力测试工具Jmeter的下载与使用

1、进入官网下载Jmeter https://jmeter.apache.org/ 国内镜像&#xff08;下载的慢的话可以用国内镜像下载&#xff09; https://mirrors.cloud.tencent.com/apache/jmeter/binaries/ 2、跳转到下载页面 3、根据不同系统下载相应版本的Jmeter压缩包&#xff0c;Linux系统下载…

精品springboot校园失物招领系统

《[含文档PPT源码等]精品基于springboot校园失物招领系统[包运行成功]》该项目含有源码、文档、PPT、配套开发软件、软件安装教程、项目发布教程、包运行成功&#xff01; 软件开发环境及开发工具&#xff1a; Java——涉及技术&#xff1a; 前端使用技术&#xff1a;HTML5,…

机器学习——CBOW基于矩阵(手动实操)

基于矩阵的CBOW基础算法&#xff0c;其实是负采样的前提算法。 主要是根据 预测准确率为22%左右 说实话。。。我已经很满意了&#xff0c;至少这个东西是可以去预测的&#xff0c;至于预测为什么不正确&#xff0c;我目前猜测主要还是跟词频有关。 在结果中&#xff0c;an…

前端架构: 脚手架之多package项目管理和架构

多package项目管理 1 &#xff09;多package项目管理概述 通常来说&#xff0c;当一个项目变大了以后&#xff0c;我们就要对这个项目进行拆分在前端当中&#xff0c;对于项目进行拆分的方式&#xff0c;通常把它称之为javascript包管理需要使用一个工具叫做 npm (Node Packag…

OpenCV实现目标追踪

目录 准备工作 语言&#xff1a; 软件包&#xff1a; 效果演示 代码解读 &#xff08;1&#xff09;导入OpenCV库 &#xff08;2&#xff09;使用 cv2.VideoCapture 打开指定路径的视频文件 &#xff08;3&#xff09;使用 vid.read() 读取视频的第一帧&#xff0c;ret…