19 设计模式之享元模式(电影院座位预定案例)

一、享元模式的定义

        享元模式是一种结构型设计模式,它通过共享对象来支持大量细粒度的对象,减少内存消耗。享元模式的核心思想是:将对象分为共享部分和非共享部分,只有共享部分是被多个对象共享的,而非共享部分则是每个对象独有的。这样,我们可以大大减少内存中的重复对象。

        在开发大型应用时,尤其是在对象数量非常庞大的情况下,内存使用和性能优化变得尤为重要。例如,在电影院座位管理、图形绘制、文字显示等应用中,我们可能会遇到大量重复的对象实例。如果每次都创建独立的对象,就会占用大量内存,从而影响系统的性能。享元模式(Flyweight Pattern)提供了一种有效的解决方案,能够减少对象的创建,优化内存使用。


二、享元模式的角色

  • 抽象享元(Flyweight):定义享元对象的接口,包含共享的部分。
  • 具体享元(ConcreteFlyweight):实现抽象享元接口,具体的享元对象共享相同的数据。
  • 非享元(UnsharedConcreteFlyweight):不需要共享的部分,通常是具体享元对象中的一部分。
  • 享元工厂(FlyweightFactory):负责创建和管理享元对象,确保共享对象的复用。

三、例子讲解:电影院座位预定

        假设我们在开发一个电影院座位预定系统,影院的座位可以通过一个编号来唯一标识。例如,座位编号为“A1”、“A2”、“B1”等。当用户选择某个座位进行预定时,我们需要管理这些座位的状态:是否被预定。

        如果我们为每个座位都创建一个独立的对象,那么当座位很多时,会消耗大量的内存。为了优化内存使用,我们可以采用享元模式,将座位的编号和预定状态作为享元对象,避免重复创建相同编号的座位对象。

1. Seat 接口

        首先定义一个座位接口,包含两个方法:reserve()用于预定座位,isReserved()用于检查座位是否已预定。

public interface Seat {void reserve();  // 预订座位的方法boolean isReserved();  // 检查座位是否已预订
}

2. ConcreteSeat 类(具体享元)

   ConcreteSeat是座位的具体实现,它包含座位编号(seatNumber)和是否预定的状态(reserved)。这部分数据是共享的,可以被多个对象复用。

public class ConcreteSeat implements Seat {private String seatNumber;  // 座位编号private boolean reserved;   // 座位是否已预定public ConcreteSeat(String seatNumber) {this.seatNumber = seatNumber;this.reserved = false;  // 默认座位未预定}@Overridepublic void reserve() {this.reserved = true;}@Overridepublic boolean isReserved() {return reserved;}public String getSeatNumber() {return seatNumber;}
}

3. SeatFactory 类(享元工厂)

  SeatFactory 是享元工厂,它负责创建并管理享元对象。它维护了一个seatMap,用于缓存已经创建的座位。当请求某个座位时,如果该座位已存在,则直接复用;如果不存在,则创建新的座位对象。

public class SeatFactory {private static Map<String, Seat> seatMap = new HashMap<>();public static Seat getSeat(String seatNumber) {// 如果座位已经存在,则复用if (!seatMap.containsKey(seatNumber)) {seatMap.put(seatNumber, new ConcreteSeat(seatNumber));  // 创建新座位}return seatMap.get(seatNumber);  // 返回已有座位}
}

4. CinemaHall 类(非享元)

  CinemaHall 是一个非享元类,它代表电影院。电影院拥有多个座位,座位的创建通过享元工厂来完成。每个电影院座位对象(Seat)都是享元对象的复用,而非享元部分是每个座位的预定状态(reserved)和座位管理(addSeats()reserveSeat())。

public class CinemaHall {private String hallName;  // 影厅名称private Map<String, Seat> seats = new HashMap<>();  // 储存该影厅的所有座位public CinemaHall(String hallName) {this.hallName = hallName;}// 使用享元工厂获取或创建座位public void addSeats(String seatNumber) {Seat seat = SeatFactory.getSeat(seatNumber);seats.put(seatNumber, seat);}// 预定座位public void reserveSeat(String seatNumber) {Seat seat = seats.get(seatNumber);if (seat != null && !seat.isReserved()) {seat.reserve();System.out.println("座位 " + seatNumber + " 已被预定");} else {System.out.println("座位 " + seatNumber + " 已被预定或不存在");}}// 显示座位状态public void showSeats() {for (String seatNumber : seats.keySet()) {System.out.println("座位:" + seatNumber + " 被预定:" + seats.get(seatNumber).isReserved());}}
}

5. 测试类(TestFlyweight

        我们可以通过测试类来验证享元模式的有效性。测试代码通过SeatFactory来创建和管理座位,确保相同编号的座位不会被重复创建,从而减少内存消耗。

public class TestFlyweight {public static void main(String[] args) {CinemaHall cinemaHall = new CinemaHall("影厅一");// 添加座位cinemaHall.addSeats("A1");cinemaHall.addSeats("A2");cinemaHall.addSeats("B1");cinemaHall.addSeats("B2");// 预定座位cinemaHall.reserveSeat("A1");cinemaHall.reserveSeat("B1");// 显示座位状态cinemaHall.showSeats();}
}

四、享元模式的优势

  1. 减少内存消耗:享元模式通过共享相同的数据来减少对象的创建,节省内存空间。
  2. 提高性能:减少不必要的对象创建,提高系统性能,尤其是在对象数量巨大时。
  3. 适用于大量细粒度对象的场景:在需要管理大量相似对象的情况下,享元模式能显著提升效率。

五、结论

        享元模式通过共享对象来优化内存使用,特别适用于系统中存在大量重复对象的场景。通过享元工厂,我们能够实现对象的复用,从而大大节省内存。在实际开发中,享元模式非常适合用于处理类似座位管理、字符渲染等需要大量对象的场景。通过本例,我们深入理解了享元模式的核心思想及实现方式,并学习了如何应用它来解决内存消耗问题。

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

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

相关文章

使用redis 的stream 做消息中间件 多线程消费消息

1.redis stream 特点 1.支持消息持久化 2.消费者组模式 3.消息确认机制 4. 消息重试机制 5. 死信队列2. 消息生产者服务 2.1 如下代码Service Slf4j public class StreamMessageProducer {Autowiredprivate StringRedisTemplate redisTemplate;private static final String S…

Python100道练习题

Python100道练习题 BIlibili 1、两数之和 num1 20 num2 22result num1 num2print(result)2、一百以内的偶数 list1 []for i in range(1,100):if i % 2 0:list1.append(i) print(list1)3、一百以内的奇数 # 方法一 list1 [] for i in range(1,100):if i % 2 ! 0:lis…

Java转C之并发和多线程

提纲&#xff1a; 概念介绍与对比概述 简述Java与C在并发和多线程方面的核心区别解释C11标准、POSIX、C11 <threads.h>、Pthread等名词 Java多线程与并发回顾 线程、Runnable、ExecutorService概念说明同步关键字与工具类含义 C并发基础 没有Java式的内置线程类&#xf…

Ubuntu系统本地化搭建Maxakb+Ollama

安装docker 最详细的ubuntu 安装 docker教程-腾讯云开发者社区-腾讯云 安装Ollama Ollama官网 执行命令&#xff1a; curl -fsSL https://ollama.com/install.sh | sh安装完成后下载模型 执行命令&#xff1a; ollama run llama3.3:70b安装MaxKb 执行命令&#xff1a; d…

基于JAVA的旅游网站系统设计

摘要 随着信息技术和网络技术的迅速发展&#xff0c;人们的生活质量和观念也在发生着改变&#xff0c;各地争相发展旅游业&#xff0c;传统的 旅游社已经无法满足人们的需求&#xff0c;旅游网站将突破传统在时间和地域的限制&#xff0c;成为方便、快捷、安全、可靠的旅游 方…

【Flux.jl】 卷积神经网络

Flux.jl 是包含卷积神经网络的, 但是官方API文件中没有给出一个完整的程序框架, 只是对所需神经元给了局部解释, 此外对 model-zoo 模型动物园中的案例没有及时跟着 Flux.jl 的版本更新, 也无法运行出来结果。 因此本文搭建了一个完整可训练的卷积神经网络。 Conv 卷积算子…

H5游戏出海如何获得更多增长机会?

海外H5小游戏的崛起给了国内众多中小厂商出海发展的机会&#xff0c;开发者如何在海外市场获得更多的增长机会&#xff1f;#APP出海# H5游戏如何在海外获得核心用户&#xff1f; HTML5游戏的开发与运营者们首先可以利用量多质高的HTML5游戏&#xff0c;维持海外用户粘性&…

Next.js系统性教学:深入理解和应用组件组合模式

更多有关Next.js教程&#xff0c;请查阅&#xff1a; 【目录】Next.js 独立开发系列教程-CSDN博客 目录 更多有关Next.js教程&#xff0c;请查阅&#xff1a; 1. 什么是组件组合模式&#xff1f; 1.1 组件组合模式概述 1.2 组件组合模式的优势 2. Next.js 中的组件组合模式…

国际荐酒师Peter助力第六届地博会,推动地理标志产品国际化发展

国际荐酒师Peter Lisicky助力第六届知交会暨地博会&#xff0c;推动地理标志产品国际化发展 第六届粤港澳大湾区知识产权交易博览会暨国际地理标志产品交易博览会于2024年12月9日至11日在中新广州知识城盛大举行&#xff0c;吸引了全球众多行业专家、企业代表及相关机构齐聚一…

Mybatis 延迟加载的实现原理详细解析

Mybatis 延迟加载的实现原理详细解析 &#xff08;1&#xff09;代理对象机制的深入探讨 代理对象的生成&#xff1a;Mybatis 使用代理对象来实现延迟加载是基于 Java 的代理机制。当开启延迟加载并且配置正确后&#xff0c;对于需要延迟加载的关联对象&#xff0c;Mybatis 会…

2024 亚马逊云科技re:Invent:Werner Vogels架构哲学,大道至简 六大经验助力架构优化

在2024亚马逊云科技re:Invent全球大会第四天的主题演讲中&#xff0c;亚马逊副总裁兼CTO Dr.Werner Vogels分享了 The Way of Simplexity&#xff0c;繁简之道&#xff0c;浓缩了Werner在亚马逊20年构建架构的经验。 Werner表示&#xff0c;复杂性总是会“悄无声息”地渗透进来…

Java Web 开发学习中:过滤器与 Ajax 异步请求

一、过滤器 Filter&#xff1a; 过滤器的概念与用途 在一个庞大的 Web 应用中&#xff0c;有许多资源需要受到保护或进行特定的预处理。过滤器就像是一位智能的守卫&#xff0c;站在资源的入口处&#xff0c;根据预先设定的规则&#xff0c;决定哪些请求可以顺利访问资源&…

ThinkPHP框架审计--基础

基础入门 搭建好thinkphp 查看版本方法&#xff0c;全局搜version 根据开发手册可以大致了解该框架的路由 例如访问url http://127.0.0.1:8094/index.php/index/index/index 对应代码位置 例如在代码下面添加新方法 那么访问这个方法的url就是 http://127.0.0.1:8094/index.…

浅谈Python库之‌Requests

一、‌Requests的介绍 Requests 是一个简单易用的 HTTP 库&#xff0c;用于发送各种 HTTP 请求。它由 Kenneth Reitz 创建&#xff0c;并广泛用于 Python 社区中。 二、‌Requests的特点 1、人性化的 API&#xff1a;简洁的接口使得编写请求代码变得简单直观。 2、跨平台&…

如何在vue中使用ECharts

一. 打开ECharts官网,点击快速入门 下面是ECharts官网的链接 https://echarts.apache.org/ 二.在vue中使用 1.首先先引入Echarts js文件 如下图&#xff0c;下面的第一张图片是官网的实现&#xff0c;第二章图片是我根据官网的实现 2.给ECharts 创建一个DOM容器 3. 使用ec…

网络原理之 IP 协议

目录 1. IP 协议报文格式 2. 网段划分 3. 地址管理 1) 动态分配 2) NAT 机制 (网络地址转换) 3) IPv6 4. 路由选择 1. IP 协议报文格式 IP 协议是网络层的重点协议。 网络层要做的事情&#xff0c;主要就是两方面&#xff1a; 1) 地址管理 制定一系列的规则&#xff…

HyperMesh CFD功能详解:后处理功能Part 2

Clips Clips 按钮包含两个工具。Box Clip用于空间上的裁剪&#xff0c;Scalar Clip可以根据物理量的范围裁剪。 示例&#xff1a;Box Clips 裁剪 示例&#xff1a;Scalar Clips 裁剪 通过裁剪&#xff0c;仅显示density范围是10~20的等值面 示例&#xff1a;显示效果控制 部分透…

Java项目实战II基于微信小程序的跑腿系统(开发文档+数据库+源码)

目录 一、前言 二、技术介绍 三、系统实现 四、核心代码 五、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末 一、前言 在快节奏的现代生活中&…

【机器学习与数据挖掘实战案例01】基于支持向量回归的市财政收入分析

【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈机器学习与数据挖掘实战 ⌋ ⌋ ⌋ 机器学习是人工智能的一个分支&#xff0c;专注于让计算机系统通过数据学习和改进。它利用统计和计算方法&#xff0c;使模型能够从数据中自动提取特征并做出预测或决策。数据挖掘则是从大型数…

windows下nacos启动报错:java.lang.unsatisfiedLinkError: C:\USers\乱码AppData\xxx.dll

问题 看了许多别的帖子&#xff0c;大家都是因为缺少dll包&#xff0c;下载安装 Microsoft Visual C 2015 Redistributable 就可以。但我试过了不行。思来想去&#xff0c;之前正常的时候用的JDK版本是17&#xff0c;后面别的项目用1.8给切换回来了。然后尝试配置环境变量将JD…