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

本文主要是介绍深入探究【观察者模式】:简单音乐会售票系统案例分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • 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 观察者*/@Overridepublic void addObserver(Observer observer) {this.observers.add(observer);}/*** 删除观察者* @param observer 观察者*/@Overridepublic void removeObserver(Observer observer) {this.observers.remove(observer);}/*** 通知观察者* @param count 通知内容*/@Overridepublic 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 通知内容*/@Overridepublic 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 通知内容*/@Overridepublic 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. 消息传递:观察者模式可以被用作消息传递的机制。不同模块之间的消息交互可以通过观察者模式实现,从而简化系统的通信方式,提高系统的灵活性和可维护性。

这篇关于深入探究【观察者模式】:简单音乐会售票系统案例分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/757151

相关文章

在C#中获取端口号与系统信息的高效实践

《在C#中获取端口号与系统信息的高效实践》在现代软件开发中,尤其是系统管理、运维、监控和性能优化等场景中,了解计算机硬件和网络的状态至关重要,C#作为一种广泛应用的编程语言,提供了丰富的API来帮助开... 目录引言1. 获取端口号信息1.1 获取活动的 TCP 和 UDP 连接说明:应用场景:2. 获取硬

Golang操作DuckDB实战案例分享

《Golang操作DuckDB实战案例分享》DuckDB是一个嵌入式SQL数据库引擎,它与众所周知的SQLite非常相似,但它是为olap风格的工作负载设计的,DuckDB支持各种数据类型和SQL特性... 目录DuckDB的主要优点环境准备初始化表和数据查询单行或多行错误处理和事务完整代码最后总结Duck

JAVA系统中Spring Boot应用程序的配置文件application.yml使用详解

《JAVA系统中SpringBoot应用程序的配置文件application.yml使用详解》:本文主要介绍JAVA系统中SpringBoot应用程序的配置文件application.yml的... 目录文件路径文件内容解释1. Server 配置2. Spring 配置3. Logging 配置4. Ma

2.1/5.1和7.1声道系统有什么区别? 音频声道的专业知识科普

《2.1/5.1和7.1声道系统有什么区别?音频声道的专业知识科普》当设置环绕声系统时,会遇到2.1、5.1、7.1、7.1.2、9.1等数字,当一遍又一遍地看到它们时,可能想知道它们是什... 想要把智能电视自带的音响升级成专业级的家庭影院系统吗?那么你将面临一个重要的选择——使用 2.1、5.1 还是

利用Python编写一个简单的聊天机器人

《利用Python编写一个简单的聊天机器人》这篇文章主要为大家详细介绍了如何利用Python编写一个简单的聊天机器人,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 使用 python 编写一个简单的聊天机器人可以从最基础的逻辑开始,然后逐步加入更复杂的功能。这里我们将先实现一个简单的

高效管理你的Linux系统: Debian操作系统常用命令指南

《高效管理你的Linux系统:Debian操作系统常用命令指南》在Debian操作系统中,了解和掌握常用命令对于提高工作效率和系统管理至关重要,本文将详细介绍Debian的常用命令,帮助读者更好地使... Debian是一个流行的linux发行版,它以其稳定性、强大的软件包管理和丰富的社区资源而闻名。在使用

Redis主从/哨兵机制原理分析

《Redis主从/哨兵机制原理分析》本文介绍了Redis的主从复制和哨兵机制,主从复制实现了数据的热备份和负载均衡,而哨兵机制可以监控Redis集群,实现自动故障转移,哨兵机制通过监控、下线、选举和故... 目录一、主从复制1.1 什么是主从复制1.2 主从复制的作用1.3 主从复制原理1.3.1 全量复制

深入理解C语言的void*

《深入理解C语言的void*》本文主要介绍了C语言的void*,包括它的任意性、编译器对void*的类型检查以及需要显式类型转换的规则,具有一定的参考价值,感兴趣的可以了解一下... 目录一、void* 的类型任意性二、编译器对 void* 的类型检查三、需要显式类型转换占用的字节四、总结一、void* 的

Ubuntu系统怎么安装Warp? 新一代AI 终端神器安装使用方法

《Ubuntu系统怎么安装Warp?新一代AI终端神器安装使用方法》Warp是一款使用Rust开发的现代化AI终端工具,该怎么再Ubuntu系统中安装使用呢?下面我们就来看看详细教程... Warp Terminal 是一款使用 Rust 开发的现代化「AI 终端」工具。最初它只支持 MACOS,但在 20

深入理解Redis大key的危害及解决方案

《深入理解Redis大key的危害及解决方案》本文主要介绍了深入理解Redis大key的危害及解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着... 目录一、背景二、什么是大key三、大key评价标准四、大key 产生的原因与场景五、大key影响与危